I see what you mean. I do understand the desire to reduce boilerplate. I'd go for a small framework like Lit (I'm sure there are even smaller ones out there) for that but I wouldn't fault anyone for writing their own. I guess, good for you you could get a paper out of it, too. It just doesn't feel particularly novel to warrant one.

> I see what you mean. I do understand the desire to reduce boilerplate. I'd go for a small framework like Lit (I'm sure there are even smaller ones out there) for that but I wouldn't fault anyone for writing their own. I guess, good for you you could get a paper out of it, too. It just doesn't feel particularly novel to warrant one.

I appreciate the sentiment; while this is, indeed, a paper, it is not a published or peer-reviewed paper. I wrote it with no intention of actually publishing it anywhere, and putting it on Arxiv is better long-term than putting it into Github or similar (I expect Arxiv to outlive any code forge).

In much the same way that I looked at web components and thought "What a nice idea. Here is how I can make this incrementally better and support client-side includes as well", I am hoping that this 100-lines of code will someday be looked at by someone else, who will (with the benefit of future knowledge and tech), then say "What a nice idea. Here is how I can make this incrementally better AND support <some future feature we cannot see right now>".

In any case, I thank you for your criticism and your time; your criticism can only make this better (for example, after reading your criticism, I think that showing a side-by-side comparison of my counter example with a custom element doing the same thing will make it more obvious why I find zjs-components more pleasant to write and use than Custom Elements).

Cheers :-)

[EDIT: Here is the comparison, in case you are still curious]

Here is the small comparison; I gave ChatGPT the ZjsComponent README.md and got it to write the example in the README as a custom element web component.

Here are the two implementations:

Implementation as a zjs-component:

    <div>
        Counter Value: <span name=counter-value>0</span>
    </div>
    <div>
        <button onclick='ZjsComponent.send(this, "increment", 1)'> +1 </button>
        <button onclick='ZjsComponent.send(this, "increment", 2)'> +2 </button>
        <button onclick='ZjsComponent.send(this, "increment", 5)'> +5 </button>
    </div>

    <script>
        function increment(amount) {
            const el = this.querySelector("[name='counter-value']");
            el.textContent = parseInt(el.textContent) + amount;
        }

        exports.increment = increment;
    </script>
Usage of zjs-component:

   <zjs-component remote-src=counter.zjsc> </zjs-component>
Implementation as a custom element web component:

    <!-- counter-component.js -->
    <script>
    class CounterComponent extends HTMLElement {
      constructor() {
        super();

        this.attachShadow({ mode: 'open' });

        this.shadowRoot.innerHTML = `
          <div>
            Counter Value: <span id="counter-value">0</span>
          </div>
          <div>
            <button data-amount="1"> +1 </button>
            <button data-amount="2"> +2 </button>
            <button data-amount="5"> +5 </button>
          </div>
        `;
      }

      connectedCallback() {
        this.shadowRoot.querySelectorAll('button').forEach(btn => {
          btn.addEventListener('click', () => {
            const amount = parseInt(btn.getAttribute('data-amount'), 10);
            this.increment(amount);
          });
        });
      }

      increment(amount) {
        const valueEl = this.shadowRoot.getElementById('counter-value');
        valueEl.textContent = parseInt(valueEl.textContent, 10) + amount;
      }
    }

    customElements.define('counter-component', CounterComponent);
    </script>
Usage of the custom element web component:

    <counter-component></counter-component>

I really like what you have done.

I know you are trying to avoid boiler plate but I'm wondering how technically difficult it would be to provide an alternative for those of us who really like named components? Something like:

  <script>
    ZjsComponent.register("counter-component", "counter.zjsc");
  </script>
Then I can just use in the named way, like:

  <counter-component start-at="100"><counter-component>

As an opt-in, probably not a bad idea. I'll look into it.