DrSensor / nusa

incremental runtime that bring both simplicity and power into webdev (buildless, cross-language, data-driven)
MIT License
4 stars 0 forks source link

HTML over HTTP #29

Open DrSensor opened 1 year ago

DrSensor commented 1 year ago

Note: all custom-element below only active when it's inside the viewport

TL;DR: HTMX but simplified with less features

<render-html
  post="api/authors?format=html"

  header="..."
  parser="json"

  body="..."
  type="text/json"
/>

It only fetch&render when one of http method (i.e POST, GET, ...) exist as attributes or it's attribute value is not empty/undefined/falsy.


https://youtu.be/LLRig4s1_yA?t=1336

<stream-html always=append src="stream/dbreport?format=html" />
const

  doc = document.implementation
    .createHTMLDocument()

, server = new EventSource(
    "stream/dbreport?format=html"
  )

doc.write("<template>")

target[host.getAttribute("always")](doc.firstChild.content)

server.onmessage = e => doc.write(e.data)
DrSensor commented 1 year ago

Food for Thought

Support binding <link href=module.js> into fetched html. The challenge here is it shouldn't add extra size[^1] for bind logic. The solution is <render-scope> must be inside <[render|stream]-html> 🤔

<render-html get=page.html>
  <link href=module.js>
  <render-scope/>
</render-html>
<!-- page.html -->

content...
  <button :: value:=count on:click=set:count>0</button>
...content

[^1]: Remember that it's non module script like render-scope.js. So you can't do code sharing via import statement.

DrSensor commented 1 year ago

This feature can be used as a foundation for fragment architecture[^1]. Maybe I should rename it as <render-fragment> 🤔

For example

<render-fragment src=/login method=GET action=prepend>
  <link href=module.js>

  <template shadowrootmode=closed>
    <!-- prepend fragment -->
    <div id=login-footer>...</div>
  </template>
</render-fragment>

By default action=replace. As for streaming a.k.a Server-Sent Event

<render-fragment
  src="/ads?change-every=5s"
  srvevent="layout message">
  <link href=/ads.css>
  <template shadowrootmode=closed>
    <slot fragment=layout>
      <img src=vacant.png>
    </slot>
    <slot fragment=message>
      contact: xxx
    </slot>
  </template>
</render-fragment>

Which create EventSource and listen to event layout and message then place each data to respective slot.

[^1]: Incremental adoption of micro-frontends with Cloudflare Workers

DrSensor commented 1 year ago

TODO: think on new syntax using additional attributes without shadow DOM

Caveat: no style scoping and DOM encapsulation


🤔

<!-- %reload.fragment.swap can be omitted which default to innerHTML -->
<div id=fragment
  -load.data=/data.json
  -load.fragment=partial.html
  %reload.fragment.swap=innerHTML>
  <!-- fallback content -->
</div>
<button %reload.fragment=#fragment>
  Swap HTML fragment
</button>
<button %reload=#fragment>
  Swap HTML fragment and refresh data
</button>
DrSensor commented 11 months ago

TODO: prevent DOM Clobbering using Sanitizer API without dropping id and name attributes