Custom elements in battle

    Good afternoon!

    The story of this publication is quite simple and perhaps familiar to many. The company develops many products - in our case, mainly for one customer. Recently, all solutions are developed for the web, and existing desktop solutions on the web are transferred.

    In this regard, if there was a desire to increase the speed of development and ensure uniformity of products, it was decided to develop a common component base. We will keep silent about how the ui kit was created and about long battles with designers, but I want to talk about the implementation of this task.
    At the front, we have democracy or even anarchy. People are free to use the solutions that they are comfortable with. At the moment there are projects in battle in AngularJS, Angular, React, Vanilla, and there are also projects in Vue for internal use. At this point, our gaze turned to web components.

    Web components


    Let's take a quick look at the concept of web components. It is based on the concept of custom elements, which allows you to extend the HTMLElement class by creating your own html tags, with business logic hidden from the user. Sounds cool, looks nice. Let's see what we can do. Hereinafter, the source code is given in typescript.

    To create a custom element, we need to do the following. Describe the class and register the component.

    export class NewCustomElement extends HTMLElement {
      constructor() {
        super();
        console.log('Here I am');
      }
    }
    if (!customElements.get('new-custom-element')) {
      /* Зарегистрируем компонент, если его еще нет */
      customElements.define('new-custom-element', NewCustomElement);
    }
    

    Further, by connecting this code to any html (compiling it in JS), we can use the component (we will come back to this, actually not, if your clients dare not use Chrome).

    Custom elements also give us some hooks for tracking component life.

    export class NewCustomElement extends HTMLElement {
      constructor() {
        super();
        console.log('I am created');
      }
      /* Вызывается каждый раз, когда элемент вставляется в DOM, согласно лучшим практикам, такие операции, как первый рендер компонента, стоит делать именно на данном шаге */
      connectedCallback() {
        console.log('Now I am in Dom');
        this._render();
        this._addEventListeners();
      }
      /* Вызывается каждый раз, когда элемент удаляется из DOM, хорошее место, чтобы произвести уборку */
      disconnectedCallback() {
        console.log('I am removed now');
        this._removeEventListeners();
      }
      /* Так объявляется список отслеживаемых атрибутов */
      static get observedAttributes() {
        return ['date'];
      }
      /* Вызывается, когда изменен один из отслеживаемых атрибутов */
      attributeChangedCallback(attrName, oldVal, newVal) {
        switch (attrName) {
            case 'date': {
              /* Обрабатываем изменение атрибута, например перерендериваем соответствующую часть компонента */
              break;
            }
         }
      }
      /* Элемент перенесен в новый документ */
      adoptedCallback() {
        /* Не знаю, что с этим делать, поделитесь в комментариях своими предложениями */
      }
    }
    

    We can also generate events in components through the dispatchEvent method

    export class NewCustomElement extends HTMLElement {
      //////
      _date: Date = new Date();
      set date(val: Date) {
        this._date = val;
        this.dispatchEvent(new CustomEvent('dateChanged', {
            bubbles: true,
            cancelable: false,
            detail: this._date
          }));
      }
      //////
    }
    

    The future has come, they said, you write the code once and use it everywhere, they said


    We got a little acquainted with the components, now I will talk about the feelings that remained after working with this technology. In general, in the article Web Components in the Real World, the author described an attitude towards technology that turned out to be very close to me.

    Let's see what advantages we got.

    • Reusable : we got a really reusable library. At the moment, it works in a vanilla project, connecting as a compiled Webpack bundle, and in an angular 7 project, connecting typescript sources in the AppModule
    • Understandable behavior : if you follow the best practices , we get components with understandable behavior that can be easily integrated into existing frameworks, for example for angular, using bananas in a box, in native applications through attributes, or working with property reflecting attributes
    • Unified style : this is some repetition of the point on reusability, but still. Now all projects use single building blocks for the construction of UI.
    • Honestly, I can’t come up with any more advantages : tell us how WebComponents helped you.

    Next, I will try to describe things that I probably did not like.

    • Labor costs : the costs of developing components are incomparably higher than the development of a framework.
    • Naming : components compete globally, so both class names and tag names must be prefixed. Given that we still have component libraries implemented under frameworks that were named as < company -component-name>, we had to prefix the web components twice with < company-wc -component-name>.
    • ShadowRoot : According to best practices, using shadowRoot is recommended. However, this is not very convenient, since there is no possibility to influence the appearance of the component from the outside. And such a need is often encountered.
    • Render : without frameworks, you have to forget about data binding and reactivity (LitElement to help, but this is another dependency).
    • The future has not come : In order to maintain user support at the old level (we have it ie11 and everything that is fresher), you have to fasten the polyphiles, es5 is the target standard, which creates additional problems.
    • Polyphils themselves : In order to get all this stuff under IE, I had to torment a lot and make some ugly decisions, as the polycoms from webcomponent break something inside the hangar, causing a call stack overflow. As a result, I had to polyfill polyphiles, having received extra dependencies.

    I do not know which conclusion to draw from all this. If Microsoft does make a chromium-based browser and stops supporting IE and Edge, then yes, it will become easier to breathe.

    There is one strange benefit: you can give the development of clean web components to novice developers - let them see how it is, write in JS without frameworks. One colleague for a long time could not understand why the change in property in the component was not immediately reflected in the DOM. Here they are people grown on frameworks. And I am the same.

    Also popular now: