LoginSignup
0
0

More than 3 years have passed since last update.

WebComponentsのHTMLImportsのグローバル汚染の悩みをすべて解決してみた

Posted at
index.html
<html>

<head>
  <link rel="import" href="/components/hello-world.html?as=hoge-piyo">
</head>

<body>
  <hello-world>動かない</hello-world>
  <hoge-piyo>動く</hoge-piyo>
</body>

</html>

components/hello-world.html
<template>
  <div id="border-div">
    <p>Hello World!!!</p>
    <slot></slot>
  </div>
</template>

<script>
  /*
  # このコードの素晴らしい点
  ## A. グローバル汚染をしていないこと
  正確にはcustomElementの名前を一つ取っているが、それは利用側でコントロール可能(後述)なので、汚染とは言わない。esmoduleと同じ。
  本当に何一つ汚染していない。クラス定義ですらも!

  ## B. 利用側のimportの仕方に依存していない
  ownerDocumentを用いているので、利用側で、どのDomにHTMLImportされているのか、Component側は意識していない

  ## C. コンポーネント名を強制させない
  デフォルトのコンポーネント名としてhello-worldを提供しているがそれだけである。
  利用側が自由に名前をつけることができる。
  他にも同盟のコンポーネントがあっても全く問題がない
  */

  {
    const ownerDocument = document.currentScript.ownerDocument;
    const moduleName = new URL(document.currentScript.ownerDocument.URL).searchParams.get('as') || "hellow-world"

    window.customElements.define(moduleName, class extends HTMLElement {
      constructor() {
        super()
        const shadowRoot = this.attachShadow({ mode: 'open' })
        const t = ownerDocument.getElementsByTagName('template')[0];
        const instance = t.content.cloneNode(true);
        shadowRoot.appendChild(instance);
      }
    });
  }
</script>

HTMLImportsを使ったときの悩み

  • customElement名が被ったら(同名のコンポーネントがあったら)死ぬ
    • → importじのURLパラメータでcomponent名を渡すことで解決
  • scriptからtemplateを参照するのに、documentから探索するのでは、コンポーネントに利用側の都合が発生して辛い
    • → ownderDocumentを用いることで解決
  • ownerDocumentはコールバック(constructorのこと)では使えないので、定数に格納する必要があるが、また一つグローバル汚染が増える
    • esnextのスコープ構文でくるむことで解決
  • ownerDocument等をスコープに隔離するとクラスで読めないし、クラスもスコープに入れると外部から参照できないジレンマ
    • → クラスを外部公開せず、直接customElement.defineにわたすことで解決
  • クラス定義自体が一つグローバル汚染になる
    • → クラスを外部公開せず、直接customElement.defineにわたすことで解決

感想

HTMLImportsの辛い部分をほぼ払拭できたのではないだろうか。
私が見た記事の中で、この自分のコードが一番筋が良いと思う。
全世界に広まり、HtmlImports自体も復権することを願う。1


  1. 本当に残念なことに、HTMLImportsはWebComponentsの中で非推奨になってしまい、今はesModuleで読み込むのが主流になっているみたいだ。最悪である。なぜなら、jsの中でhtmlをベタ書きしなくてはならないから。WebComponentsがただの改悪版Reactに成り下がったのである。(Mozillaが実装しなかったかららしい?)ともかくいくら残念とはいえHTMLImportsはスタンダードではない。 

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0