この広告は、90日以上更新していないブログに表示しています。
Any Holy Grail for Web Components?の翻訳。
Web Componentsの歴史は輝かしいものではなかった:
Shadow DOMを必要としない、または使用しない場合、これまでに成功してきたライブラリやプロジェクトで採用されてきたように、コンポーネントが広く採用される可能性が高くなる。しかしまだ他の弱みが残る:
ホスティングしているページからテーマを継承する可能性のあるParagraphを表現したいとしよう。そして、JSを経由して魔法のようなことができる「Special paragraph」として配信したいとすれば、おそらく次のようにするだろう:
// the JS sideclass SpecialPextends HTMLElement{ constructor(){/* setup it once */}}customElements.define('special-p', SpecialP);// the HTML side<special-p> <p> The actual content </p></special-p>
代償として、どのような形であれShadow DOMを使用すると、ホスティングしているサイトのテーマを反映できる<p>タグをつけなくてもロジックとレイアウトの両方が肥大化する。
グレースフルエンハンスメントについて言うと、カスタム要素をサポートしていないブラウザには<spacial-p>タグをどう処理すればいいのかさえわからない。
私たちが望んでいたのは、Paragraphを簡単に設定する方法だけだった。
2KBの小さなWicked Elementsライブラリは、すでに説明したような問題を解決する素晴らしいソリューションになっている。それはひとつのポリフィルも必要とせずにIE9までサポートする。カスタム要素をまったく使用せずに、DOMに到達するあらゆる要素に、カスタム要素のようなイベントを別のAPIを介して公開する。
// the JS sidewickedElements.define('p.special',{ init(){/* setup it once */}});// the HTML side<pclass="special"> The actual content</p>
頭を使う必要がないほど簡単なので、ぜひこの小さなライブラリを試してみてほしい。しかしまだいくつかの問題点が残っている:
Web標準についてさらに説明する前に、私が考えるReactの人気を高めるために役立ったことを要約したい:
Web標準もこのリストの最初の2つの点を、より良くはないにしても確実にカバーしている。しかし3つ目の点を超えることはできない:
// the React JS sideclass Specialextends React.Component{ render(){return <p>{this.props.text}</p>;}}// still the React JS side ...const el = <Special text="The actual content" />;
そしてstyled-componentsを追加する……。標準技術を通して私たちがそのような経験に近づき、楽になる可能性はあるだろうか?
残念ながらまだすべてのブラウザで利用できるわけではないが、すでにカスタム要素をサポートしている場合(例:Safari)ならたった1Kのポリフィルを使用すれば、このプリミティブはカスタム要素の標準的な表現力だけでwickedElementの能力を得るための最善の妥協策になる。
// the JS sideclass SpecialPextends HTMLParagraphElement{ constructor(){/* setup it once */}}customElements.define('special-p', SpecialP,{extends:'p'});// the HTML side<p is="special-p"> The actual content</p>
結果として、これまでに説明したいくつかの課題が解決された:
したがって、不足しているのは次の通り:
簡単に言うと、これまで押し戻されてきた組み込みの拡張とユーザーランドの標準ベースのソリューションを組み合わせてJSで宣言的レイアウトを作成することは、標準的な世界でReactエクスペリエンスをシミュレートするための完璧な組み合わせかもしれないということだ。
このライブラリ名(和訳すると異教、異端、異説)は、一般に受け入れられている概念とは大きく異なる概念を組み合わせているため、これ以上適切なものはないと思う。
SpecialPコンポーネントの最も基本的な例を次に示す:
// the JS sideimport{render, html, define} from'heresy';define(class Specialextends HTMLParagraphElement{static tagName ='p';});// the HTML side (SSR ready)<p is="special-heresy"> The actual content</p>// or ... the JS siderender(document.body, () => html` <Special> The actual content </Special>`);
🤯
待って……。何が起こっている?
.nameを使用してレジストリ名を定義し、末尾に-heresyを付けて、カスタム要素レジストリに対して常に有効な名前にする.tagNameを使用して、表すべき実際のDOM要素の種類を指定する。組み込みのカスタム要素であればどんな要素でも構わない(option、tr、td、select、li、input、label……)is=属性が検出されればすぐにアップグレードされる.nameを記述した場合、テンプレートリテラルでレイアウトを宣言するために使用されるエンジンは、<p is="...">として自動的に変換されて膨張しない。宣言されたノードは実際にはDOM上に存在し(これらを参照することもできる)、仮想的なものは存在しない。つまりカスタム要素はユーザーがハンドリングできるインスタンスであるその結果、JSXと非常によく似た方法で宣言することができる。
the best part of `heresy` is that layout can look exactly like in JSX, but there's no indirection whatsoever to what you write and what you get/target 🎉pic.twitter.com/tKZpLrvsKE
— Andrea Giammarchi (@WebReflection)April 27, 2019
import{render, html, define} from'heresy';define(class Specialextends HTMLParagraphElement{static style = selector => ` ${selector}{ transition: background 300ms;} ${selector}:hover{ background-color: silver;} `;static tagName ='p';});
このCSSは、クラスの静的styleメソッドを介してクラス宣言ごとに1回だけ注入され、スタイル設定に使用される名前を含む文字列であるセレクタを引数として渡す。
この例では、引数はp[is="special-heresy"]になる。
styleは単なる静的メソッドであるため、実行時にSASSやLESSのようなトランスフォームを介して変換された文字列を返すこともできる。
import{render, html, define} from'heresy';define(class Specialextends HTMLParagraphElement{static tagName ='p'; #props ={}; get props(){returnthis.#props;} set props(props){this.#props = props;this.render();} render(){this.html`${this.props.text}`;}});render(document.body, () => html` <Special props=${{text:'The actual content'}}/>`);
lighterhtmlのおかげで、カスタム要素には任意のゲッターまたはセッターを指定できるので、任意の種類の値を即座に渡すことができる。
ポリフィルとツールを適切に組み合わせることで、HeresyはIE9でも動く。
その方法を理解するには、基本的なライブデモまたはそのソースコードを参考にできる。
私に休憩させてください😂
このプロジェクトはまだ初期の段階で実験的なものだが、すでにいくつか有望な成果が出ている。たとえばこの古典的なTodoデモ(ソース)は現在Chrome Canaryでしか動作しないが、これはトランスパイルを行わずに最新のJSの機能をベースにしているからだ。
次のようなもの:
// ...render(){this.html` <input placeholder="type item" onkeydown=${this}> <Hide onchange=${this}/> <ul>${this.items.map( data => html`<Item data=${data}/>` )}</ul>`;}
このカスタム要素ベースのアプローチを使うのはとても楽しいが、私はまだこれを使って具体的なアプリを作っていないことを覚えておくように。そしてlightterhtmlよりもhyperHTMLの方が、その.bindメカニズムのおかげでより適切なのではないかと考えている。
しかしプロトタイプ作成にはlighterhtmlが最も簡単なツールだ。当面私が理解したいのは、コミュニティがこのようなソリューションを気に入って、興味を持っているかどうか。そうすればおそらくいつかSafariの開発者もネイティブの組み込み機能を提供して、誰もがポリフィルをドロップできるようになるだろう。
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。