[HN Gopher] Streaming HTML out of order without JavaScript
       ___________________________________________________________________
        
       Streaming HTML out of order without JavaScript
        
       Author : goranmoomin
       Score  : 209 points
       Date   : 2024-03-01 09:37 UTC (1 days ago)
        
 (HTM) web link (lamplightdev.com)
 (TXT) w3m dump (lamplightdev.com)
        
       | djxfade wrote:
       | This looks very interesting, I was not aware that this was
       | possible natively without JS.
       | 
       | What's the browser support like?
        
         | MindSwipe wrote:
         | Seems like browser support is pretty universal, even says so in
         | the article
         | 
         | > All browsers support streaming HTML
         | 
         | And the caniuse is promising: https://caniuse.com/?search=slot
        
           | csande17 wrote:
           | <slot> has been around for a while in Web Components; the
           | relevant feature here is probably the (much newer)
           | shadowrootmode attribute:
           | https://caniuse.com/?search=shadowrootmode
           | 
           | But you can already do a lot with regular streaming and using
           | CSS Grid, inline <script> tags, etc to move stuff around the
           | page.
        
         | mikedelfino wrote:
         | Chrome, Edge and Safari since March 2023; Firefox since
         | February 2024.
         | 
         | https://caniuse.com/mdn-html_elements_template_shadowrootmod...
        
       | mg wrote:
       | At the core, this seems to be about shadowrootmode=open, a new
       | html feature which already landed in Chromium and Safari:
       | <div>           <template shadowrootmode=open>             This
       | is <slot name=a></slot> and <slot name=b>           </template>
       | <span slot=b>sunny</span>           <span slot=a>funny</span>
       | </div>
       | 
       | renders as:                   This is funny and sunny
       | 
       | So it looks like HTML got a bit of a native template system now.
       | 
       | What I have been wanting for decades is a native template system
       | in HTML which supports urls. Similar the the script tag, but
       | which loads html:                   <html url="/header.html">
       | <html url="/content.html">         <html url="/footer.html">
       | 
       | I always wondered why this was never implemented. It seems such a
       | basic functionality which would allow to comfortably build
       | websites in a modular way without scripts or serverside
       | processing.
        
         | reddalo wrote:
         | It reminds me of FrontPage extensions, "good" times...
        
         | robin_reala wrote:
         | While it needs a little JS to initialise, that's easy enough to
         | do with custom elements: https://github.com/gustafnk/h-include
        
         | hiimshort wrote:
         | The last example reminds me of the once-proposed html imports
         | feature. It was being pushed by Google back when Polymer was a
         | thing and would've given us actual web components delivered as
         | html documents with full support for html, css, and js just
         | like we use normally. If I remember correctly there were a few
         | issues with the approach that needed to be resolved and nobody
         | stepped up to make it a reality. So instead we got the custom
         | elements spec years later which only implemented a small
         | percentage of what made html imports useful.
        
           | troupo wrote:
           | In the end it was only Firefox who implemented HTML Imports,
           | and Google has gone mad and pushed everything in to
           | Javascript.
        
             | hinkley wrote:
             | They went Golden Hammer on v8.
        
             | spankalee wrote:
             | That is not what happened at all. Firefox never shipped
             | HTML Imports.
        
               | troupo wrote:
               | Well I'll be! In my mind I had this clear picture of
               | Firefox implementing it.
               | 
               | It correct, it was only Chrome:
               | https://caniuse.com/?search=html%20import
        
         | easyThrowaway wrote:
         | This looks exactly like svelte named slots syntax:
         | https://blog.logrocket.com/comprehensive-guide-svelte-compon...
        
           | vmfunction wrote:
           | SPA like React, Vue, Angular, Svelt, solid, should be not
           | needed if HTML implemented these features. Or make JSX a
           | standard again such as E4X.
        
             | afavour wrote:
             | All of the libraries you've listed offer features above and
             | beyond what we're talking about here. Plus, web components
             | exist, they do most of it and yet the libraries still
             | exist.
        
               | williamcotton wrote:
               | See: $ becoming querySelector.
        
             | eyelidlessness wrote:
             | I'm all for standardizing JSX, but I think we should be
             | clear that its only similarity to E4X is syntax. The latter
             | corresponds directly to the browser/HTML/XML DOM, whereas
             | the former corresponds to nothing in particular except the
             | semantics you might give it. I'd also be interested in a
             | revival of E4X as a potential implementation of
             | standardized JSX, but I'd be disappointed (and I think many
             | JSX users would be too) if the standardization coupled the
             | two completely.
        
           | montroser wrote:
           | Yes, many frameworks including svelte took heavy inspiration
           | from various parts of the Web Components specs, including
           | named slots. So, this is the original thing that svelte and
           | others copied.
        
           | paulddraper wrote:
           | And that's not a coincidence; svelte chose to borrow that
           | concept from Web Components.
        
         | Joe8Bit wrote:
         | The "template" use case was a very common one from
         | iframes/framesets in the early 2000s, and the markup often
         | looked a lot like your desired example.
         | 
         | My memory's hazy, but I remember it becoming more and more
         | complex to maintain as the web's security and performance model
         | evolved, as you needed to manage and secure all of these
         | disparate, discrete DOM trees in the same page context.
         | 
         | Wouldn't what you suggested just been "reinventing"
         | frames/framesets if you added the ability to arbitrarily pull
         | in templates via the network?
        
         | hnbad wrote:
         | https://www.w3.org/TR/html-imports/
         | 
         | There are long and boring reasons why it never went anywhere.
        
         | ibotty wrote:
         | It's also in firefox, at least in 123.
        
         | Devasta wrote:
         | https://www.w3.org/TR/xinclude
         | 
         | The W3C specced something out around 20 years ago, but browser
         | devs are allergic to all things XML.
        
           | hanniabu wrote:
           | Because it doesn't have to be xml.
           | 
           | I agree partials should be a native feature.
        
           | dheera wrote:
           | The devs aren't allergic to XML, they're allergic to MBA
           | types telling the org that
           | 
           | "we need to embrace agility and scrumble to use the latest
           | Big Data and Web 3.0 technologies such as XML"
           | 
           | "XML powers fortune 500 businesses"
           | 
           | etc
           | 
           | That said, XML parsnips are almost universally shitty.
           | Python's beautifulsoup is about 100 times harder to use than
           | json.
        
             | cqqxo4zV46cp wrote:
             | What? This feels like a largely unrelated rant.
        
         | judiisis wrote:
         | <frame> is already there
        
         | xnx wrote:
         | I used to do a lot with Apache server side includes and always
         | wished there was a client side option.
        
         | megaman821 wrote:
         | Includes are different than this. Pretend the template is site
         | header, site nav, body content, and footer; each being a slot.
         | The server then streams body content, site header, site nav and
         | footer in that order. Now more important content gets rendered
         | first without any JS.
         | 
         | This technique would be a lot more usable though when shadow
         | roots become open style-able. It is kinda funky having to apply
         | your CSS separately to the layout regions that live in your
         | shadow dom.
        
         | judiisis wrote:
         | can be done using service workers or workbox(abstraction to sw)
        
         | masswerk wrote:
         | > I always wondered why this was never implemented
         | 
         | Wasn't this in HTTP/1.1 (1997), where you could send chunks to
         | anything that could have a target attribute? (As multipart HTML
         | relied on http chunks, which suffered poor support by the
         | Windows http stack, this quickly vanished and in the 2000s
         | support was stripped from browsers. I think, Chrome was the
         | first to do so. Personal note: I once wrote a chat server,
         | which relied on this technology - and it worked pretty well,
         | outside IE.)
         | 
         | Another way this had been once supported was in Netscape 4.0's
         | layers (1997), which could have a `src` attribute and worked
         | just as you would expect. (However, support for this vanished
         | with the first iterations, about the same time JS-styles were
         | switched to CSS. It had been definitely a feature in the NS 4.0
         | prerelease versions. Especially the capability to re-link the
         | `src` attribute by JS or by a link target was nice.) NS 4 also
         | featured extended HTML entities, which could render JS
         | expressions in place and also provided a mechanism for
         | conditional comments - so, had we followed that route, HTML
         | would have been already a templating language.
        
         | taf2 wrote:
         | That was like what ESI (Edge Side Includes) allowed from
         | Akamai. Perhaps had the founder[1] of Akamai not been killed in
         | the world trade towers we'd have had that in the standard...
         | 
         | [1] https://en.wikipedia.org/wiki/Daniel_Lewin
        
         | ndriscoll wrote:
         | xslt is a native template system that has includes: <xsl:copy-
         | of select="document('/header.html')"/>
         | 
         | xhtml/xslt still works today (though browsers are stuck on v1).
         | It's a declarative template system with a pretty powerful
         | pattern matching system (xpath). You can also extract fragments
         | from external documents or store them into variables. e.g.
         | <xsl:copy-of
         | select="document('/content.html')/body/div[2]/ul/li/a/@href"/>
         | will copy all urls from a list inside the 2nd div. Or instead
         | of second div in the body, you could search for a div with an
         | id or specific attributes or specific children or whatever
         | pattern you want.
         | 
         | Why webdevs forsook xml will always be a mystery to me.
         | Particularly given that they now use things like JSX.
        
           | Pwntheon wrote:
           | I can only speak for myself, but the few times I encountered
           | xslt in the past it was in the context of bulky and verbose
           | SOAP services. The syntax felt off to me (and still do).
           | 
           | I think this was at the time I was learning jquery and using
           | css selector syntax for finding elements, and the difference
           | between that and xpath was pretty stark.
           | 
           | I basically (probably with insufficient knowledge) filed xslt
           | away with vb and tables for formatting as old, complex and
           | soon to be replaced
        
             | mananaysiempre wrote:
             | The syntax felt off to Juniper, too, so they made their
             | own: https://juniper.github.io/libslax/slax-manual.html.
             | Loses homoiconicity to some extent, sure, but outputting
             | XSLT using XSLT never was particularly pleasant.
        
               | Exoristos wrote:
               | I can confirm that SLAX is a pleasure to use. Pity it
               | hasn't had adoption outside Juniper to my knowledge.
        
           | kroltan wrote:
           | I just recently moved my personal homepage to XML + XSLT. Not
           | a pro at it at all though. I did enjoy the process, I like
           | the idea of building the website out of data + templates, but
           | that's not unique to XSLT.
           | 
           | Besides some papercuts / browser bugs like "refreshing the
           | page desyncs the inspector", the main issue I find with it is
           | I don't see how I can modify things dynamically?
           | 
           | By the time JS runs, it's on the resulting HTML DOM, not the
           | XML source, so I can't add elements dynamically respecting
           | the XSLT stylesheet?
           | 
           | Also, XML must be well-formed and have a single root, I can't
           | stream it out on the server piecewise?
           | 
           | With those 2 limitations, I don't see any advantages over any
           | other server-side templating language, it just duplicates
           | work that could happen once in a SSG or at least cached in a
           | CDN, onto every client computer.
        
             | ndriscoll wrote:
             | Right, unless you run a javascript xslt processor, you
             | can't do things after page load. There's at least one
             | javascript implementation that lets you do data binding to
             | do dynamic page updates, but I'm not familiar with it.
             | 
             | The main advantage for simple things is that you don't need
             | an application server or compiler. It's all static files,
             | and it's all built right into the browser so easy to get
             | started with. For less simple things, it should be easier
             | to cache since you can separate out user data and have the
             | bulk of the information you send be the static template
             | (which the user can cache).
             | 
             | I suppose maybe that last point is why people use
             | javascript frameworks for static pages (so they can send a
             | static, cached js file and then small payloads for user
             | data), which seems like overkill to me.
             | 
             | It would be nice if browsers supported streaming xml. Of
             | course streaming xml exists (e.g. XMPP). It's not really
             | any different than json: the spec said you need to have a
             | single root object, and then someone wrote a spec that says
             | you don't need to do that.
        
         | mhitza wrote:
         | Probably because HTML specs were quasi frozen for a long time.
         | As another comment said, XSLT supports it. XHTML conformance
         | would have made the web development world stricter, and more
         | flexible. Thank you Microsoft for holding the web back.
         | 
         | There are also [Server Side
         | Includes](https://en.wikipedia.org/wiki/Server_Side_Includes)
         | which were used for that.
         | 
         | Funny enough, I've used SSIs first and last time around 2020.
         | The project I worked on had a heavily cached landing page (for
         | performance reasons), but needed a way to swap out the homepage
         | banners based on product releases, and the easiest way around
         | that was to output a SSI directive for a separate banners
         | endpoint.
        
         | spankalee wrote:
         | Firefox supports declarative shadow DOM too now!
         | 
         | There's a long-standing WHATWG feature request open for client-
         | side includes here: https://github.com/whatwg/html/issues/2791
         | 
         | And several userland custom element implementation, like
         | https://www.npmjs.com/package//html-include-element
         | 
         | One of the cool things that you can do with client-side
         | includes and shadow DOM is render the included HTML into a
         | shadow root that has <slot>s, so that the child content of the
         | include element is slotted into a shell implemented by the
         | included HTML.
         | 
         | This lets you do things like have the main page be the per-page
         | content and the included HTML be a heavily cached site-wide
         | shell, and then another per-user include with personalized HTML
         | - all cached appropriately.
        
           | ndriscoll wrote:
           | > This lets you do things like have the main page be the pre-
           | page content and the included HTML be a heavily cached site-
           | wide shell, and then another per-user include with
           | personalized HTML - all cached appropriately.
           | 
           | If you can do your includes at page load time, you've been
           | able to do this for 25 years with xslt; it's been built into
           | the browser almost since the beginning of the web!
           | 
           | I've played around with doing exactly that: include a
           | `/myinfo.xml` document that has information about your user,
           | and then the rest of the page template just grabs
           | `$myinfo/user/@name` or whatever wherever it needs. The neat
           | thing is it has graceful degradation by default: if the
           | request fails, then your include will be empty and you can
           | treat it as a logged out page. So you can e.g. display the
           | username and logout button in the top right if logged in, or
           | a login button if not. You can also e.g. include a CSRF token
           | in your info document and plop that into any forms in your
           | page by just doing `value="{$myinfo/csrf-token}"` or
           | whatever.
        
         | Lorin wrote:
         | So... iframes that stay in the context of the parent element?
         | You'd need some tight CSP coupling to prevent it from being a
         | security disaster.
        
         | wildpeaks wrote:
         | It seems supported in most browsers, not just Chromium and
         | Safari: https://caniuse.com/mdn-
         | html_elements_template_shadowrootmod...
        
         | hanniabu wrote:
         | Native partials should be awesome
        
         | jwells89 wrote:
         | The lack of native HTML includes is a big reason why I picked
         | up just enough PHP to write functional pages back in the early-
         | mid 00s. Not having to manually propagate changes to e.g.
         | navbars across a whole site was mind blowing.
        
         | lenkite wrote:
         | We had HTML imports a decade ago
         | https://web.dev/articles/imports
         | 
         | This would have been better than world peace. But this
         | threatened a lot of warmonger advertisers. So it was
         | "deprecated" and then obliterated.
        
       | alexey2020 wrote:
       | That's cool and definitely the future of HTML streaming,
       | 
       | it simplifies things a lot: js enabled out-of-order streaming
       | leads to SEO problems and frameworks usually need to come up with
       | workarounds - detect bots and turn of streaming for that case.
       | 
       | With such technique no workaround is needed, less things to worry
       | about.
       | 
       | Excellent!
        
         | quickthrower2 wrote:
         | This might lead to SEO problems as you wont know what the SE
         | will see rendered i it's text only view.
        
       | quickthrower2 wrote:
       | You could possibly do this using a flexbox?
       | 
       | https://developer.mozilla.org/en-US/docs/Web/CSS/order
        
         | felixfbecker wrote:
         | Flexbox order doesn't affect accessibility tree order, so
         | that's bad for accessibility. DOM order should make semantic
         | sense.
        
           | ricardobeat wrote:
           | Managed tabindex would solve that. Sounds like a nightmare to
           | maintain though.
        
             | felixfbecker wrote:
             | tabindex only affects tab order (of interactive elements),
             | not the order that a screen reader navigates and reads out
             | content (including non-interactive elements)
        
           | megaman821 wrote:
           | There is a new reading order attribute coming to fix this.
        
             | Lorin wrote:
             | Why wouldn't they just amend the existing feature so it's
             | accessible?
        
               | _heimdall wrote:
               | Backwards compatibility I'd assume. Someone could have
               | taken advantage of the fact they flex order and
               | accessibility order are different.
               | 
               | Changing the functionality now would break those sites,
               | adding a new CSS prop would make the fix opt-in.
        
             | felixfbecker wrote:
             | There already is one in ARIA that supports this: aria-owns
             | [1] and to some degree aria-flowsto [2]
             | 
             | But with everything in ARIA, it always depends on real-
             | world support of screen readers, which is very poor. You
             | have to work with what actually works unfortunately.
             | 
             | Imo changing order just to change the streaming order for a
             | tiny performance gain is not worth breaking the UX for
             | people with accessibility needs.
             | 
             | [1] https://developer.mozilla.org/en-
             | US/docs/Web/Accessibility/A... [2]
             | https://developer.mozilla.org/en-
             | US/docs/Web/Accessibility/A...
        
           | paulddraper wrote:
           | And how is <slot> for accessibility?
        
         | alvarlagerlof wrote:
         | Only if the elements are siblings
        
       | Alifatisk wrote:
       | The site loads pretty slowly for me [1], and when they site has
       | fully loaded the list has already been completed, there is no
       | streaming from what I can see. Is Firefox the reason here?
       | 
       | 1. https://check-host.net/check-report/16234f41keed
        
         | luke-stanley wrote:
         | It worked fine for me in Firefox.
        
         | exchemist wrote:
         | Also for me, both on Firefox and Edge - I'm wondering if it's
         | to do with being behind a corporate proxy that MITMs everything
         | and might be buffering rather than passing through partial
         | respones, or has a much higher threshold before streaming?
         | 
         | If that is the reason, it'll provide an (even more than
         | usually) poor experience for those behind such a proxy
        
         | bmacho wrote:
         | The site[0] works for me in Edge, and Firefox, as intended. The
         | slow loading is the point, you should see how it updates real
         | time, which doesn't happen to you for some reason. As other
         | comment suggests, maybe something on your network doesn't like
         | tiny (~42 characters) HTML fragments.
         | 
         | [0] : https://ooo.lamplightdev.workers.dev/
        
         | netghost wrote:
         | Firefox just added support for declarative shadow dom, so that
         | might be it if you're not on the latest version.
         | 
         | Alternatively I could imagine some kind of proxy between you
         | and the site buffering things up.
        
           | Alifatisk wrote:
           | > some kind of proxy between you and the site buffering
           | things up.
           | 
           | Yeah I think that might be it, because it works fine on FF
           | (iOS) outside.
        
       | myfonj wrote:
       | Real fun begins when you realize that the streamed content can
       | react to interactions that user submits from the streamed page:
       | form targetted into hidden iframe or any other mean of issuing
       | HTTP request back to the server and handling data it can react to
       | in next streamed chunk. This way you can have for example "CSS
       | only chat" [1], or basically anything, since the chunk with new
       | data can contain style directives hiding the old data...
       | 
       | [1] https://github.com/kkuchta/css-only-chat
        
       | danielvaughn wrote:
       | Neat, but what would be the intended use case for something like
       | this? I can imagine a scenario where one part of the UI may take
       | extra time to load, so you would defer it to let the other parts
       | load first. Is there another reason I'd want this?
        
         | kevincox wrote:
         | I used similar streaming HTML for my RSS reader. When you
         | import subscriptions it can take a while as each feed is
         | fetched so I use streaming HTML to show the progress of each
         | feed as it is imported. This provides meaningful progress
         | updates to the user.
         | 
         | However previously the limitation was that the content needed
         | to be more or less in order (you could use some CSS tricks but
         | they were limited). Using this trick I would be able to render
         | the full list of pending feeds then insert a result as each
         | finishes being fetched.
         | 
         | In fact it seems that for each slot the last element will be
         | used. So you can even create live-updating pages based on this
         | which is really cool. For example imaging you had a score
         | ticker. You could push an update to that region of the page
         | every time the score changes.
         | 
         | I think this is definitely a niche use case, but it is very
         | nice to support this without JS. Of course in all but the
         | simplest use cases JS may still be the right solution. For
         | example if the connection drops for any reason there is no
         | mechanism for showing the user an error, let alone retrying.
        
           | netghost wrote:
           | I was just trying that out, I _think_ it just concatenates
           | all the content into the slot, but maybe there's a way to do
           | that?
        
             | crooked-v wrote:
             | In that case, just use a selector like `.content-
             | item:not(:last-child)` to hide everything but the last item
             | that was added.
        
         | crooked-v wrote:
         | Dealing with loading in a smart way (even small amounts of
         | loading), without extra JS overhead, is the fundamental use
         | case.
         | 
         | For a comparison, basically the entire bajillions of man-hours
         | that have gone into React Server Components [1], and all the
         | many, many complications and footguns inherent in their
         | approach, is trying to solve the same problem.
         | 
         | [1]: https://nextjs.org/docs/app/building-your-
         | application/render...
        
       | k33n wrote:
       | The big application for this is multicasting html via UDP. P2P
       | web apps could leverage this.
        
       | politelemon wrote:
       | This helped me with a 'visual' understanding of what's happening,
       | go to
       | 
       | view-source:https://ooo.lamplightdev.workers.dev/
       | 
       | then watch the bottom of the page as the new `<span slot=...>`
       | elements come in. As they come in, the browser's, well, slotting
       | the contents into the corresponding slot in the template.
        
       | commonenemy wrote:
       | This brings the memory of BigPipe, facebook has had this years
       | ago (using JS of course).
        
       | msoad wrote:
       | Let's say I streamed the first chunk with a little JavaScript,
       | would that JavaScript be able to listen to future chunks coming
       | in? In a real application it is crucial to be able to update your
       | frontend state once new data is ready.
       | 
       | First thought is [mutation
       | observer](https://developer.mozilla.org/en-
       | US/docs/Web/API/MutationObs...) but that seems too deep into the
       | weeds
        
         | AirMax98 wrote:
         | I'd assume that the only reason one would need to know if
         | chunks were incoming is to indicate a loading state in
         | disparate parts of your webpage, e.g. chunk B has some widget
         | that indicates chunk A is loading. In this case, you can
         | probably work off the assumption that loading is the default
         | initialization state, and use JS to communicate to the
         | disparate parts of your page once on chunk A load. There may be
         | something different that you're thinking about here though.
        
         | eyelidlessness wrote:
         | Another approach would be to correlate observation with
         | specific custom elements. You can define them in the first
         | chunk, then use their connectedCallback method to observe them
         | as they arrive. The benefit of an approach like this is that
         | the custom element lifecycle APIs are synchronous (which is
         | also the drawback of the approach, and where MutationObserver
         | is more appropriate if that synchrony is a concern).
        
         | andipodean wrote:
         | Perhaps the most horrible JavaScript I ever wrote did something
         | like this, and has been very useful for over a decade and still
         | going strong.
         | 
         | It's a log file that starts with a header: just a script tag
         | with some JS, followed by a special string (I used a special
         | HTML comment as a boundary indicator). The server then appends
         | its logging to this file in a web hosted directory.
         | 
         | The JS periodically does an XHR of it's own location.href,
         | polling itself. It then splits on the special boundary string,
         | thus collecting the latest log data, parses it to generate
         | pretty/coloured/linked HTML, and updates the current page
         | according (and controls scrolling if required).
         | 
         | This gives you a log file that's continuously being appended
         | to, but can be visited in the browser using any static file
         | serving and automatically updates as it's populated.
        
         | its-summertime wrote:
         | Mutation observer is pretty easy once you get used to it, just
         | look for data you care about and ignore the rest.
         | 
         | Alternatively, I think slotting raises an event, so you could
         | use js to remove the pre-existing content when new content gets
         | added
        
       | h43z wrote:
       | If I add multiple slots with the same name it shows all of them.
       | <div id=t>           <template shadowrootmode=open>
       | <slot name="s1">s1</slot>             <slot name="s2">s2</slot>
       | <slot name="s3">s3</slot>           </template>         </div>
       | <script>           setTimeout(_=> t.innerHTML += `<span
       | slot="s3">three</sp>`, 1000)           setTimeout(_=> t.innerHTML
       | += `<span slot="s1">one</sp>`, 2000)           setTimeout(_=>
       | t.innerHTML += `<span slot="s2">two</sp>`, 3000)
       | setTimeout(_=> t.innerHTML += `<span slot="s1">ONE!!</sp>`, 4000)
       | </script>
       | 
       | I guess there is no way to replace a slot, again and again?
        
       | heh89898000 wrote:
       | Very cool. Perhaps this could be used for non-JS CAPTCHAs, since
       | it would force the bot to wait for a few seconds.
        
       | davepeck wrote:
       | Fun stuff!
       | 
       | The underlying `swtl` library is itself pretty interesting.
       | 
       | Note the use of `delayed(...)` in the blog's example code: a
       | promise in a tagged template.
       | 
       | SWTL's `html` allows for this (I think the blog's example follows
       | the simple case here
       | https://github.com/thepassle/swtl/blob/main/html.js#L23). And
       | SWTL's `render` method races the promises
       | (https://github.com/thepassle/swtl/blob/main/render.js#L120)
       | outward.
        
       | egberts1 wrote:
       | This is a long overdue but promising trend toward a JavaScript-
       | less website.
       | 
       | Yeah, I am one of the few outliers who still host JS-free out of
       | cybersecurity reasons.
        
       ___________________________________________________________________
       (page generated 2024-03-02 23:02 UTC)