logoalt Hacker News

pointlessone06/17/20251 replyview on HN

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.


Replies

lelanthran06/17/2025

> 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>
show 1 reply