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

Support named export (top-level binding) #63

Open DrSensor opened 1 year ago

DrSensor commented 1 year ago

Warning: this pattern is highly experimental

<render-scope>
  <link top-level href=module.js>
  <template shadowrootmode=closed>
    <button :=counter>0</button>
    <span :: text:=set:total>0</span>
  </template>
</render-scope>
function increment() { this.value++ }

export function counter(element) {
  element ??= this ?? <button/>
  element.addEventListener("click",  increment)
  return element
}

👣 Footgun: how do you bind variable (i.e total)?


export let total
// total += 1
// require compiler
// (maybe compile to class
//  with @bind accessor
//  for the sake of performance
//  😂)

export const total = {} // total.value += 1 // works without compiler but weird


---
The reason I'm interested in named export is because of [`handleEvent()`](https://dom.spec.whatwg.org/#dom-eventlistener-handleevent) pattern in `class`[^1]

```html
<render-scope>
  <link top-level href=module.js>
  <template shadowrootmode=closed>
    <button :=Counter>0</button>
  </template>
</render-scope>
export class Counter {
  value = 0
  constructor(element = <button/>) {
    element.addEventListener("click",  this)
    return Object.setPrototypeOf(element, new.target.prototype)
  }
  handleEvent(event) {
    switch (event.type) {
      case "click":
        this.increment()
        break
      default:
        this.value = +event.currentTarget.value
    }
  }
  increment() { this.value++ }
}

use module in other area or projects

import { Counter } from "./module.js"
for (const input of document.querySelectorAll("input.counter")) {
  const counter = new Counter()
  input.after(counter)
  input.addEventListener("change", counter)
}

[^1]: DOM handleEvent: a cross-platform standard since year 2000

DrSensor commented 1 year ago

Seems the only compromise for avoiding data-binding footgun is to only allow named exports for handling ref Element #9. Basically named export must be a function or class. With this limitation, top-level attribute is not necessary.

DrSensor commented 1 year ago

I think I will go with ! prefix and only limit named/top-level export function for ref element, event handler, and setter/getter (choose one). Would be nice if I can support this context too.