Angular Elements を用いた Web Components 製 UIライブラリの提供

Angular Elements を用いた Web Components 製 UIライブラリの提供

GDG DevFest 2020
mini ng-japan 2020

Reference 👀
- Angular.io
- Angular elements overview
- Angular Roadmap
- blog.lacolaco.net
- Angular Elementsの現在地 (2020 Summer)
- Angular Elements: Composable Definition Pattern
- open-wc.org
- Web Component Libraries
- stackoverflow.com
- How to call a method on a Angular Web Component (Custom Element)
https://stackoverflow.com/questions/52797841/how-to-call-a-method-on-a-angular-web-component-custom-element
- Call Angular web component method (CustomElement)
https://stackoverflow.com/questions/62804721/call-angular-web-component-method-customelement

885a8df80c5e2ce0594116bb3b79db10?s=128

Masashi Kondo

October 17, 2020
Tweet

Transcript

  1. Angular Elements を⽤いた Web Components 製 UIライブラリの提供 Kondo Masashi GDG

    DevFest 2020 mini ng-japan 2020
  2. About Me

  3. Agenda Angular Elements を⽤いた Web Components 製 UIライブラリ開発について、 ⾃社事例を元に説明します。 1.

    サービス紹介 2. Angular Elements 3. Safie Web Components 4. 開発時の課題と対策
  4. •••• サービス紹介

  5. クラウド録画サービス︓Safie ネットワークカメラの映像をクラウドに保存。 いつでもライブや録画映像を視聴。 Web の映像ビューアーは Angular 10 で開発。 サービス紹介

  6. Safie Viewer DEMO

  7. 映像視聴 UI ライブラリ ユーザーが⾃分のビジネスとコラボして映像を使えるようにする。 そのためには⾃社サイト以外でも録画映像を⾒れるようにしたい。 録画映像を扱う UI ライブラリとしてのニーズが出てきた。 ライブラリは標準規格である Web

    Components で提供。 Angular Elements を⽤いて実装した。 サービス紹介
  8. •••• Angular Elements

  9. Angular Elements Angular の Components を Web Components (Custom Elements)

    に変換し て出⼒。 Angular Elements import { NgModule, Injector } from '@angular/core'; import { createCustomElement } from '@angular/elements'; import { AComponent } from './components/a.component'; @NgModule({ declarations: [ AComponent, ], }) export class AppModule { constructor(private injector: Injector) {} ngDoBootstrap() { const AComponentElement = createCustomElement( AComponent, { injector: this.injector } ); customElements.define('a-component', AComponentElement); } }
  10. Angular Elements @Input は Attribute に @Output は Custom Event

    に マッピングされる。 ライフサイクルフックも可能。 Angular Elements import { Component, Input } from '@angular/core'; @Component({ template: 'A_Component', }) export class AComponent { private _type = 'normal'; @Input() text = ''; @Input() set type(value: string) { this._type = value; } get type() { return this._type; } @Output() change = new EventEmitter(); }
  11. Angular Elements フレームワークに依存しないコ ンポーネントを簡単に作成でき る。 Angular Elements <body> <a-component text="GDGdevFest"></a-component>

    <script src="https://wc.download.url/"></script> <script> const aComponent = document.querySelector('a-component'); aComponent.type = "normal"; aComponent.addEventLister('change', () => { console.log('changed'); }) </script> </body>
  12. •••• Safie Web Components

  13. Safie Web Components フレームワークに依存しない Web Components 製のUIライブラリ。 映像視聴に特化したUIを提供。 Safie Web

    Components
  14. Safie Web Components DEMO

  15. •••• 開発時の課題と対策

  16. 開発時の課題と対策 Angular Elements を⽤いた開発で⼯夫したこと。 特に通常の Angular 開発で普段気にしないことについて説明する。 1. ViewEncapsulation.ShadowDom 2.

    Attribute Mapping (@input) 3. Error Handling 4. Composable Definition Pattern 5. Lazy Loading (Component) 開発時の課題と対策
  17. ViewEncapsulation.ShadowDom 開発時の課題と対策

  18. ViewEncapsulation .ShadowDom そのまま Angular Elements を Custom Elements にする と

    Scoped CSS が適応されま せん。 Scoped CSS を使うには Components で encapsulation を設定。 開発時の課題と対策 ••••• import { Component, ViewEncapsulation, // } from '@angular/core'; @Component({ template: ' <span class="light">Light Component</span> ', }) export class LightDomComponent {} @Component({ template: ' <span class="shadow">Shadow Component</span> ', encapsulation: ViewEncapsulation.ShadowDom, // }) export class ShadowDomComponent {}
  19. ViewEncapsulation .ShadowDom Web Components は ShadowDom を使って Scoped CSS を実現する。

    createCustomElement する Components で ShadowDom を指定する。 開発時の課題と対策 ••••• DEMO
  20. Attribute Mapping 開発時の課題と対策 •••••

  21. Attribute Mapping Angular Elements では @input() が付与されたプロパ ティを Custom Element

    の属 性として扱う。 開発時の課題と対策 ••••• import { Component, Input } from '@angular/core'; @Component({ template: 'Component_A', }) export class AComponent { private _type = 'normal'; @Input() text = ''; @Input() set type(value: string) { this._type = value; } get type() { return this._type; } } // <a-component text="sample" type="special"></a-component> //
  22. Attribute Mapping 今回は <video> のように play() 、 pause() などのメソ ッドを定義する必要があった。

    Angular Elements には function を定義する術が無 い。 開発時の課題と対策 ••••• import { Component, Input } from '@angular/core'; @Component({ template: 'Component_A', }) export class AComponent { _timestamp = new Date().getTime(); @Input() mute = false; // 参照可能 play() { // is not a function console.log('call play'); } @Input() pause() { // is not a function console.log('call pause'); } @Input() get timestamp() { // 参照可能 return this._timestamp; } }
  23. Attribute Mapping 関数を定義する術が無いので、 別 Components に play() と pause() を定義。

    Custom Elements から instance として Components を取得して実⾏ する。 開発時の課題と対策 •••••
  24. Attribute Mapping Custom Element になる外側 の Component に instance を

    @Input の Getter で定義。 内側の Component に関数を 定義する。 開発時の課題と対策 ••••• import { Component, Input } from '@angular/core'; @Component({ template: 'OuterComponent', }) export class OuterComponent { innerComponent = new InnerComponent(); @Input() get instance() { // return this.innerComponent; } } @Component({ template: 'InnerComponent', }) export class InnerComponent { play() { // console.log('call play'); } pause() { // console.log('call pause'); } }
  25. Attribute Mapping 出⼒した Custom Element か ら instance を取得。 instance

    に対して play() 等 の関数を呼ぶ。 開発時の課題と対策 ••••• <body> <outer-component></outer-component> <script src="https://wc.download.url/"></script> <script> const outerComponent = document.querySelector('outer-component'); const innerComponent = outerComponent.instance; function play() { innerComponent.play(); // call play } function pause() { innerComponent.pause(); // call pause } </script> </body>
  26. Error Handling 開発時の課題と対策 •••••

  27. Error Handling 利⽤者は Web Components で発⽣したエラーを検知するこ とが出来ない。 <video> の様に onerror

    を実 装する必要がある。 開発時の課題と対策 ••••• import { Component } from '@angular/core'; @Component({ template: ' <input type="button" value="throw" (click)="onClick()" > ', }) export class AComponent { onClick() { throw Error('throw Error!!!'); // } }
  28. Error Handling @Output で Custom Event と して実装するのが良いが、前述 の件があったので instance

    で EventEmitter を使い実装し た。 開発時の課題と対策 ••••• <!-- Safie Web Components --> <body> <safie-streaming-player></safie-streaming-player> <script src="https://wc.download.url/"></script> <script> const safieStreamingPlayerElement = document.querySelector('safie-streaming-player'); const safieStreamingPlayer = safieStreamingPlayerElement.instance; safieStreamingPlayer.on('error', (error) => { console.error(error); }); </script> </body>
  29. Composable Definition Pattern 開発時の課題と対策 •••••

  30. Composable Definition Pattern 今後の課題として、定義する Components が増えると Module (Component) の共 通部分への依存が増えてくる。

    これを効率化し、オーバーヘッ ドを減らしたい。 開発時の課題と対策 •••••
  31. Composable Definition Pattern Angular Elements は複数の Component (Module) を⼀ つの

    Web Components とし て定義できる。 開発時の課題と対策 ••••• import { NgModule, Injector } from '@angular/core'; import { createCustomElement } from '@angular/elements'; import { AComponent } from './components/a.component'; import { BComponent } from './components/b.component'; @NgModule({ declarations: [ AComponent, BComponent ], }) export class AppModule { constructor(private injector: Injector) {} ngDoBootstrap() { const AComponentElement = createCustomElement( AComponent, { injector: this.injector } ); const BComponentElement = createCustomElement( BComponent, { injector: this.injector } ); customElements.define('a-component', AComponentElement); customElements.define('b-component', BComponentElement); } }
  32. Composable Definition Pattern ⼀つの Web Components と して出⼒することで、 Component (Module)

    の他 に bootstrapping や <script> のロードに掛かる共 通のオーバーヘッドも削減でき る。 開発時の課題と対策 •••••
  33. Lazy Loading 開発時の課題と対策 •••••

  34. Lazy Loading 更に効率を上げるため、Lazy Loading を活⽤する。 共通部分をダウンロードし、必 要な Components をロードす ることができる。

    開発時の課題と対策 •••••
  35. Lazy Loading Angular Elements での Lazy Loading デモ 開発時の課題と対策 •••••

    DEMO
  36. おわりに Angular Roadmap では今後Ivyでの最適化や、Optional ngModule などが予定さ れており、Angular Elements で出⼒されるWeb Componentsもその恩恵を受けれ

    ることを期待しています。 Web Components の開発経験はほぼ0でしたが、 Angular Elements のお陰で想 定より簡単でした。是⾮使って頂ければと思います。
  37. Finish! Enjoy GDG DevFest and ng-japan

  38. Github https://github.com/MssKnd/angular-elements-demo

  39. Reference Angular.io Angular elements overview Angular Roadmap blog.lacolaco.net Angular Elementsの現在地

    (2020 Summer) Angular Elements: Composable Definition Pattern open-wc.org Web Component Libraries stackoverflow.com How to call a method on a Angular Web Component (Custom Element) Call Angular web component method (CustomElement)
  40. This slides powered by Marpit (VSCode Plugin)