An experiment to allow different versions of the same web component on one page

栏目: IT技术 · 发布时间: 4年前

内容简介:WARNINGThis is an experimental feature, use it at your own risk and be sure to understand its. No big applications are usingComplex Web Component applications are often developed by several teams across organizations. In that scenario it is common that sha

WARNING

This is an experimental feature, use it at your own risk and be sure to understand its. No big applications are using scoped-elements yet - so there is no proof yet if it works in production. This page focuses on in depth explanations as it should help foster a discussion on scoping .

Complex Web Component applications are often developed by several teams across organizations. In that scenario it is common that shared component libraries are used by teams to create an homogeneous look and feel or just to avoid creating the same components multiple times, but as those libraries evolve problems between different versions of the same library may appear, as teams may not be able to evolve and update their code at the same velocity. This causes bottlenecks in software delivery that should be managed by the teams and complex build systems, to try and alleviate the problem.

Scoped Custom Element Registries is a proposal that will solve this problem, but until it is ready or a polyfill becomes available, we have to scope custom element tag names if we want to use different versions of those custom elements in our code. This package allows you to forget about how custom elements are defined, registered and scopes their tag names if it is necessary, and avoids the name collision problem.

npm i --save @open-wc/scoped-elements

Use case and demos

Consider the following setup

  • Team Blue owns Page A
  • Team Green owns Page B
  • Team Black owns Feature A & B
  1. Everything is good andyour app is live [ code ] with both pages.
  2. Team Black releases a new version ( 2.x ) of Feature B which unfortunately needs to be breaking in order to support new use-cases.
  3. Team Blue (on Page A ) does not use any of those new use cases and they have a tight deadline to meet so they can not update right now.
  4. Team Green (on Page B ) has to deliver an important functionality to your end users but they need to upgrade to Feature B 2.x since it can only be solved with this new version.
  5. Since Feature A 1.x & 2.x are both used in the same app, this will lead to nested dependencies, which then will lead to catastrophic failure, and errors [ code ].

Two possible solutions come to mind:

  1. Temporarily (!) allow to ship similar source code (most breaking releases are not a total rewrite) and scope them via @open-wc/scoped-elements ; see the "fixed" examplewith-scope [ code ] running with nested dependencies.
  2. Synchronizing updates of shared dependencies - e.g. make sure Team Blue & Team Green always use the same version when releasing. This can be a viable solution however it comes with a high organizational overhead and is hard to scale up (for 10+ teams)

Technical explanation of scenario

The simplified app has the following dependencies

  • app
    • page-a
      • feature-a 1.x
      • feature-b 1.x
    • page-b
      • feature-a 2.x
      • feature-b 1.x

which leads to the following node_modules tree

├── node_modules
│   ├── feature-a
│   ├── feature-b
│   ├── page-a
│   └── page-b
│       └── node_modules
│           └── feature-a
├── demo-app.js
└── index.html

To demonstrate, we made three demos:

  1. before-nesting [ code ] In this demo, everything works fine as Page A and B both are using the same version of Feature A

  2. no-scope [ code ] Feature A version 1.x and 2.x are imported via self registering entry points which leads to the following error message, because the feature-a component tries to register multiple times:

    Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry': the name "feature-a" has already been used with this registry
      at [...]/node_modules/page-b/node_modules/feature-a/feature-a.js:3:16
  3. with-scope [ code ] This example successfully fixes the problem by using createScopedHtml on both Page A and Page B .

createScopedHtml defines your custom element classes and creates a unique scoped tag for each of them if you need to use multiple versions of an element. In case those classes were already defined, it will return the previously defined tag.

Then, the html function provided by the createScopedHtml method transforms the template literal into another one replacing the tags used by the user by the ones defined by the custom elements. Finally, the transformed template literal is going to be processed by lit-html .

<my-button>${this.text}</my-button>

becomes: <my-button-3>${this.text}</my-button-3>

  1. Import createScopedHtml from @open-wc/scoped-elements .

    import { createScopedHtml } from '@open-wc/scoped-elements';
  2. Import the classes of the components you want to use.

    import MyButton from './MyButton.js';
    import MyPanel from './MyPanel.js';
  3. Create the html function and define the tags you want to use for your components.

    const html = createScopedHtml({
      'my-button': MyButton,
      'my-panel': MyPanel,
    });
  4. Use your components in your html.

    render() {
      return html`
        <my-panel>
          <my-button>${this.text}</my-button>
        </my-panel}>
      `;
    }
import { css, LitElement } from 'lit-element';
import { createScopedHtml } from '@open-wc/scoped-elements';
import MyButton from './MyButton.js';
import MyPanel from './MyPanel.js';

const html = createScopedHtml({
  'my-button': MyButton, // <-- binds the element to a tag in your html
  'my-panel': MyPanel,
});

export default class MyElement extends LitElement {
  static get styles() {
    return css`
      .panel {
        padding: 10px;
        background-color: grey;
      }
    `;
  }

  static get properties() {
    return {
      text: String,
    };
  }

  render() {
    return html`
      <my-panel>
        <my-button>${this.text}</my-button>
      </my-panel}>
    `;
  }
}
  1. Components imported via npm MUST NOT be self registering components. If a shared component (installed from npm) does not offer an export to the class alone, without the registration side effect, then this component can not be used. E.g. every component that calls customElement.define .

    export class MyEl { ... }
    customElement.define('my-el', MyEl);

    Or uses the customElement typescript decorator

    @customElement('my-el')
    export class MyEl { ... }

    Only side effects free class exports may be used

    export class MyEl { ... }
  2. Every (!!!) component that uses sub components need to use scoped-elements . Any import to a self registering component can result in a browser exception - completely breaking the whole application.

  3. Imported elements need to be fully side effect free (not only element registration)

  4. Currently, only lit-html is supported (though other rendering engines could be incorporated in the future).

  5. You can not use tag selectors in css, but you could use an id, a class name or even a property instead.

    :no_entry_sign: my-panel {
      width: 300px;
    }
    :white_check_mark: .panel {
      width: 300px;
    }
  6. You can not use tag names using javascript querySelectors, but you could use an id, a class name or even a property instead.

    :no_entry_sign: this.shadowRoot.querySelector('my-panel');
    :white_check_mark: this.shadowRoot.querySelector('.panel');
  7. Using scoped-elements may result in a performance degradation of up to 8%.

  8. Loading of duplicate/similar source code (most breaking releases are not a total rewrite) should always be a temporary solution.

  9. Often, temporary solutions tend to become more permanent. Be sure to focus on keeping the lifecycle of nested dependencies short.

We are using Tachometer to measure the performance penalty of using the scoped elements feature. The chosen test application is a slight variation of the Polymer Shop Application .

This is an example of the results obtained running the performance test.


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

计算几何

计算几何

奥罗克 / 机械工业 / 2005-4 / 49.00元

本书介绍了在计算机图形学、机器人和工业设计领域逐渐兴起的几何算法的设计和实现。计算几何中使用的基本技术包括多边形三角剖分、凸包、Voronoi图、排列、几何查找、运动计划等。虽然自主处理只涉及数学基础知识领域的一部分,但是它却和当今该研究领域的前沿课题相关。因此,专业的程序员会发现本书是一本不可多得的参考书。   与上一版相比,本版包括以下几方面的新内容:多边形三角剖分的随机化算法、平面点定......一起来看看 《计算几何》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

SHA 加密
SHA 加密

SHA 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具