web-dev-qa-db-ja.com

Webコンポーネントでの外部JSライブラリの使用

Polymer 2を使用してWebコンポーネントを開発しています。Webコンポーネントで使用するように特別に設計されていないサードパーティのJavaScriptライブラリを利用したいと考えています。私の知る限り、これを行う唯一の方法は、WebコンポーネントのHTMLファイル内に、ライブラリを参照する<script>タグを含めることです。

私はこれを行うことでいくつかの問題を見ることができ、それらを回避する方法があるかどうか、そして実際にこの方法でサードパーティのライブラリを含めることは悪い習慣と見なされているかどうかを知りたいです。

  1. 外部ライブラリは、ページ上の他のコンポーネントに表示されるグローバル変数を設定し、Webコンポーネントが互いに壊れたり、ホストされているページを壊れたりする可能性があります。カプセル化は Webコンポーネントを使用する大きな利点の1つ として宣伝されることが多いため、これは問題のようです。

  2. 外部ライブラリはDOMクエリまたは更新を実行する可能性があり、それらを使用しているWebコンポーネントのshadow-domにアクセスできないため、外部ライブラリは実際にはまったく機能しないか、ホスティングページのDOMを更新してカプセル化を解除する可能性があります。

それで、何かが足りないのですか、それとも外部ライブラリをWebコンポーネントに含めるのは本当に悪い考えですか?もしそうなら、既存の膨大な数のJSライブラリを利用することができないため、このテクノロジーの大きな制限のように思えます。

16
codebox

document.querySelectorのようなことを行う外部ライブラリがある場合、2つの選択肢があります。

  1. コンポーネントでShadowDOMを使用しないことを選択します。それがオプションではない場合、または本当にあなたが本当にシャドウDOMを使用したい場合:
  2. 常にdocumentを使用する代わりに、ルート要素を指定できるようにサードパーティライブラリを変更する必要があります。

これらの2つのオプションを超えると、documentがすべてで機能することを前提とするサードパーティのライブラリを使用できなくなる可能性があります。

他のオプションは、サードパーティのライブラリを再評価して、それが[〜#〜]本当に[〜#〜]かどうかを確認することです。

私のチームでは、確かなロジックだけではないサードパーティのライブラリを使用していません。 moment.js のようなものは単なるロジックであり、問​​題なく使用できます。

しかし、jQueryのようなものは?おい!コンポーネントにそのようなものが必要なのはわかりません。

幸運を!

6
Intervalia

私は実際には昨日同じ問題に対処する必要があったので、タイミングが良い;)私の場合、最初のページのビューには2つのセクションがあり、ラジオボタンが1つあります。オートコンプリートが有効になる(または無効のままになる)

このシナリオでは、Google Mapsライブラリなしでページをロードし、Webコンポーネントが完全にレンダリングされた後にgmapsコードを動的にロードする方がはるかに効率的でした。これにより、インタラクティブにかかる時間が50%短縮されました。 。

注:loadGoogleMaps()メソッドとinitCalled変数宣言はクラスの外にあるため、webコンポーネントの外にあります(私はそれらをimportステートメントの下に置いています)。また、あなたの質問には関係がなかったので、例からクラスコードのほとんどを省略しました:)

import { html } from '@polymer/lit-element';
import { PageViewElement } from './page-view-element.js';
import { SharedStyles } from './shared-styles.js';
import '@vaadin/vaadin-radio-button/vaadin-radio-button.js';
import '@vaadin/vaadin-radio-button/vaadin-radio-group.js';
import { spinner } from './my-icons.js';

let initCalled;

function loadGoogleMaps() {
  //Only load gmaps if it has not been loaded before (tracked by the initCalled flag)
  if (!initCalled) {
    //Dynamically import the library and append it to the document header
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.async = true;
    script.onload = function () {
      //Code to execute after the library has been downloaded parsed and processed by the browser starts here :)
      initCalled = true;

      //TODO: Refactor this DOM traversing logic
      const searchAutocomplete = document.querySelector('my-app').shadowRoot.querySelector("home-property-view")
        .shadowRoot.querySelector('home-property').shadowRoot.querySelector("input[type='text']");

      const autocomplete = new google.maps.places.Autocomplete(
        searchAutocomplete, {
          types: ['address'],
          componentRestrictions: {  //Limit to only US addresses
            'country': 'us'
          }
        });

      autocomplete.addListener('place_changed', function () {
        const place = autocomplete.getPlace();
        dispatchEvent(new CustomEvent('propertyAddressChanged', {
          bubbles: true,
          composed: true,
          detail: place
        }));
      });
    };
    //Specify the location of the gmaps library
    script.src = '//maps.googleapis.com/maps/api/js?v=3.33&key=<YOUR-API-KEY-GOES-HERE>&libraries=places';

    //Append it to the document header
    document.head.appendChild(script);
  }
}

class HomeProperty extends PageViewElement {
  //....omitted class code for brevity...

  _didRender(props, changedProps, prevProps) {
    loadGoogleMaps();
  }

  //....omitted class code for brevity...
}
3
univ