‹ BackHN Continuity

Thread

Why don't more developers “use the platform”?

297 points · 314 comments · vinhnx

  1. jchw · · focus · HN ↗
    For one thing, I just genuinely think WebComponents are a badly designed API that is weird and hard to use (how many people are using WebComponents without at least Lit, if not something much bigger?), and React is a relatively well-designed library that isn't really that bloated. There's not really much of a point in trying to argue since this is inherently subjective and people with different values are going to irreconcilably disagree. But, if you don't respect that some people hold this position, we're not going to make any progress towards a consensus.

    On the note of <dialog>, I recently tried to use <dialog> in a (React) application, and it did work pretty well, but I also found that in Firefox it is only practically possible to do a fade-in animation, not a fade-out one. That isn't really a critical issue for me, it is just an animation after all, but I find it unfortunate. I also find <dialog> to be a weirdly shaped API too: I don't really hate it, but I don't love it either. It feels awkward.

    I find this implicit view that developers that, for example, prefer React over WebComponents are making a suboptimal choice to be rather condescending and not really in the spirit of trying to see things from the other side. Wouldn't you want to focus on the strongest arguments and not the weakest ones? Maybe you've literally never heard anyone complain about WebComponents or Shadow DOM, but if so, I find that surprising. Certainly here on HN, I've seen a fair bit of WebComponents hate.

    I do, FWIW, realize that I've particularly focused on WebComponents, which this article doesn't actually name directly. But, I assume we're not talking about ditching React to implement our own component framework on top of the traditional DOM APIs, because that's what React already does...

    1. mg · · focus · HN ↗
      What do you not like about WebComponents?

      Say we want to make an icon that when clicked shows how often it was clicked. The webcomponent code seens quite sane to me:

         class HelloIcon extends HTMLElement {
            connectedCallback() {
              this.clickCount = 0;
      
              this.innerHTML = `
                <button class="icon">:)</button>
                <dialog>
                  <p>Hello, I was clicked 0 times</p>
                  <button class="close">Close</button>
                </dialog>
              `;
      
              const icon = this.querySelector('.icon');
              const dialog = this.querySelector('dialog');
              const closeBtn = this.querySelector('.close');
              const dialogText = this.querySelector('p');
      
              icon.addEventListener('click', () => {
                this.clickCount++;
                dialogText.textContent = `Hello, I was clicked ${this.clickCount} times`;
                dialog.showModal();
              });
      
              closeBtn.addEventListener('click', () => dialog.close());
            }
          }
      
      Try it here:

      <a href="https:&#x2F;&#x2F;plnkr.co&#x2F;edit&#x2F;0XUOLyM52xfFiIBu?open=index.html&amp;preview" rel="nofollow">https:&#x2F;&#x2F;plnkr.co&#x2F;edit&#x2F;0XUOLyM52xfFiIBu?open=index.html&amp;previ...

      1. hnedeotes · · focus · HN ↗
        (preface by saying I use webcomponents regularly, I can show you a game that&#x27;s currently online where they&#x27;re used extensively)

        I don&#x27;t really understand why people are complaining that this is unmaintainable on the replies to this snippet but there&#x27;s plenty of things with webcomponents in general that could be better done on the browser side.

        For one the innerHTML (or some new method) should be able to reference a `template` directly. If you want to use templates you need to do:

        ``` const template = document.getElementById(&quot;templates-materialization-base&quot;).content;

        this.appendChild(template.cloneNode(true)); ```

        And if you want to use templates then you need to render the templates in a part of the dom that is parsed before this JS is run - there&#x27;s no way of specifying dependencies for this kind of things - which is a short-coming of the platform as a whole.

        One the same topic there&#x27;s no way of providing an url for retrieval of a fragment that contains templates and have it parsed directly and available to subsequent JS if you could do:

        `&lt;HTML-FRAGMENT href=&quot;&#x2F;my-endpoint&#x2F;returns-templates.html&quot; required=&quot;true&quot; id=&quot;MAIN_FRAGMENTS&quot;&gt;` or doing `fetch(&quot;&#x2F;my-endpoint&#x2F;returns-templates.html&quot;, {DOCUMENT_ID=&quot;MAIN_FRAGMENTS&quot;)` would parse the result and make it available to the browser engine then you could have on subsequent JS:

        `&lt;script requires=&quot;MAIN_FRAGMENTS&quot; wait=&quot;GLOBAL_LOADING_INDICATOR`&gt;....&lt;&#x2F;script&gt;` or in a file&#x2F;module `requires DOCUMENT_ID: MAIN_FRAGMENTS` and the file&#x2F;script execution would block until that would be available, just that would go a long way. You could specify fragments (the component DOM templates to be used) that are needed for the webpage to work at all, fragments that would only show loading for their own content, etc (you could style the TAG with a pseudo-state indicator, so if it had a wait not resolved yet, CSS could target it with `MY-TAG:state(waiting)`).

        Another issue is `attributeChangedCallback` - this doesn&#x27;t take into account how most of the times one can&#x2F;will update the attributes of an element, so it fires once for each change, even if you made X changes in one swoop, making it so that you have to have to make a more complex &quot;update_render&quot; function to work around that, or lots of small functions that are composable (ideally, but not practical or wanted in many cases where the whole thing is to be treated as a single update) or create a `batched_attributeChangedCallback` that you implement yourself as part of a class mixin and then extend the HTMLElement class on declaration and use that, because most of the times you want to re-do&#x2F;update the whole component and when you have multiple properties (equivalent to react props and similar in other frameworks) and multiple components this can result in expensive updates to the page that the user feels as sluggish on their end. Something like:

        `batched_attributeChangedCallback(attributes, old_values, new_values, batch_timer_window: 200, batch_timer_fn: true)` where the default for the batch window is 200ms, but can be provided a `fn` that does the evaluation to. So even if the updates are done independently but under the timer window they&#x27;re batched instead of run 1 by 1 (or immediately if the `fn` returns true, defaulting to true when it&#x27;s independent 1 by 1 updates).

        I usually have a function `_set_handlers(boolean)` that is used on connected and disconnected callback but this is just plain js organisation:

        ``` _set_handlers(toggle) { let act = toggle ? &quot;addEventListener&quot; : &quot;removeEventListener&quot;;

          window[act](&quot;some-window-event&quot;, this._maybe_ready);
          this[act](&quot;some-component-event&quot;, this._some_fun.bind(this));
        } ```

        And the connectedCallback just calls `this._set_handlers(true)` and disconnected `this._set_hanlders(false)`.

        I use them, you can use them to great effect, but I think the biggest problem is the lack of connection between the different APIs. This includes things like indexDB as well, it&#x27;s not very complex, but it does look messy on &quot;first-glance&quot;. Like your example, but when you actually read it, it&#x27;s pretty straightforward (ignoring the bad&#x2F;non-existing functionality&#x2F;APIs). The same with SSE. This could be a great solution for many things, but you always need to wire up yourself how it works. Would be great if you could declare &quot;receiving beacons&quot;, at the page level, or component level, with automatic teardown on removal&#x2F;navigation. So a component could have `static SSE_BEACONS() { [&quot;<a href="https:&#x2F;&#x2F;something.com&#x2F;path" rel="nofollow">https:&#x2F;&#x2F;something.com&#x2F;path&quot;] }` and would mark the state of the component automatically with `BEACONS: [WAITING | CONNECTED | ERROR]`

        The loading indications, still seems strange that after 40 years of web development the transition between webpages are basically &quot;white page&quot;, &quot;freeze current view&quot;. Just having some way of specifying loading states would make any webpage feel 90% of a webapp between page transitions. Make it be a restricted subset of CSS that can be included as a header at the document top level and cached for subsequent visits `&lt;LOADING_STYLES version=X&gt;&lt;MAIN&gt;background-color: white;&lt;&#x2F;MAIN&gt;&lt;LOADING_INDICATOR&gt;shape: square; rotation: 1s; main-color: blue; secondary-color: turquoise&lt;&#x2F;LOADING_INDICATOR&gt;&lt;&#x2F;LOADING_STYLE&gt;`. This would also allow to evolve it while maintaining strict backwards compatibility by starting from a very basic set of possible values - but just this would make website loading a much more app like experience. It could be used together with webcomponents too: `&lt;MY-WEBCOMPONENT ...&gt;&lt;LOADING_STYLES&gt;...&lt;&#x2F;LOADING_STYLES&gt;&lt;&#x2F;MY-WEBCOMPONENT&gt;` that then could be automatically derived from the `states` I mentioned prior.

        Anyway... Spent too much time with frameworks and webcomponents by now. It probably would also make writing code for LLMs less error prone.

        Just a rant, don&#x27;t take it too seriously, but sometimes I wonder with all the resources poured into frameworks by the big Gs, that must amount to millions and millions of dollars when you take into account the salaries some of the people working on them take, if it wouldn&#x27;t have been better spent somewhere else on the &quot;base&quot; implementation.

Open on Hacker News to reply ↗

Unofficial Hacker News client; not affiliated with Y Combinator.