stencilがよさそうな話

Roppongi.js #5

2018/8/23

自己紹介

  • 西田雅博
  • Mercari/Merpay
  • Goでサーバーサイド
    • Scala
    • Angular, React

GitHub: adwd

Twitter: @adwd118

 

stencil

  • ionicチームによるWeb Components/PWAコンパイラ
    • Custom Elementsライブラリをビルド
    • PWAなアプリケーションをビルド
  • Version 0.12.0-3
  • AngularとReactを混ぜたみたいなシンタックス
  • VirtualDOM
  • TypeScript製 

stencilを始める

# npm 6 or higher

# create component library
$ npm init stencil component my-components

# create stencil application
$ npm init stencil app my-app

# 2018/8/22時点ではこれがないとbuildでこける :innocent:
$ npm i -D request

$ npm start

$ npm test

$ npm build
  • いい感じのプロジェクトをスキャフォールドしてくれる
import { Component, State, Prop } from '@stencil/core';

@Component({
  tag: 'my-sample',
  shadow: true,
})
export class MySample {

  @Prop() user: { id: string, name: string };
  @State() books: Array<{ id: string, title: string, author: string }> = [];
  
  componentWillLoad() {
    return fetch(`/api/users/${this.user.id}/books`)
      .then(response => response.json())
      .then(data => this.books = data);
  }

  render() {
    return (
      <ul>
        {this.books.map(book => <li>{book.author}: {book.title}</li>)}
      </ul>
    );
  }
}

Syntax

Stencil Componentで

できること

最近のFWでできることはたいていできる

  • State, Props
  • ライフサイクルメソッド
  • Context API
  • Functional Component (undocumented)
  • など

Custom Elementsを

使うFWとして

  • 標準のCustom Elementsでできないこと
    • attributeにカスタムイベントのコールバック関数を与える
      • 標準ではaddEventListener
      • stencil以外で作ったCustom ElementsもOK
document.querySelector('my-sample').addEventListener('myMessage', ev => {
  console.log(ev.detail);
});
<my-sample onMyMessage={ev => console.log(ev.detail)}></my-sample>
@Component({
  tag: 'my-sample',
})
export class MySample {

  @Event() myMessage: EventEmitter<string>;

  render() {
    return (
      <div>
        <button onClick={() => this.myMessage.emit('hello')}>send message</button>
      </div>
    );
  }
}

Custom Elementsを

使うFWとして

  • 標準のCustom Elementsでできないこと
    • 文字列以外の型をpropsに与える
@Component({
  tag: 'my-sample',
})
export class MySample {
  @Prop() private user: { name: string, age: number };

  render() {
    return (
      <div>{this.user.name}: {this.user.age + 10}</div>
    );
  }
}
<my-sample user={{ name: 'bob', age: 100 }}></my-sample>
<!-- name:bob, age:110 になる。 '100' + 10で '10010'にならない -->

アプリケーションFWとしてのStencil

  • 自前でRouterを持ってる
  • SSRできる
  • ServiceWorkerをいい感じにやってくれる
  • Prerendering機能がある

Prerendering

<head>
  <link href="/build/app.css" rel="stylesheet">
  <script data-resources-url="/build/app/">...</script>
</head>
<body>
  <app-root></app-root>
</body>
<head>
  <style data-styles="">
    ...
  </style>
</head>

<body>
  <app-root ssrv="0" class="hydrated">
    <div ssrc="0.0">
      ...
    </div>
  </app-root>
  <script data-resources-url="/build/app/">...</script>
</body>
$ npx stencil build
$ npx stencil build --prerender
www/
  index.html
  profile/
    index.html
  about/
    index.html
www/
  index.html

Prerendering

  • より速いFirst meaningful paint, SEO
  • SSRほど複雑なことをしなくていい
  • isServer context
import { Component, Prop } from '@stencil/core';

@Component({ tag: 'my-sample' })
export class MySample {
  @Prop({ context: 'isServer' }) private isServer: boolean;

  componentWillLoad() {
    if (!this.isServer) fetch('/api/users').then(...);
  }

  render() {
    ...
  }
}

まとめ

  • stencilでCustom Elementsを中心としたライブラリ・アプリケーションを作れる
  • Custom Elementsを便利に使える機能を持っている
  • Prerenderingよさそう
  • TypeScript製でいい感じのSyntax
  • lit-htmlでいいんじゃないの説
  • これからに期待!!!
Made with Slides.com