Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
2024年2月 エンジニア イベント資料 カーナベル株式会社
Slide 2
Slide 2 text
本日は遠方よりご参加ありがとうございます! 本日のアジェンダ ● 前半の部 ○ イントロ ○ カーナベルを支える技術について (〜11:15) ○ Web Components(Lit)を利用したモダンなUI開発体験 (~12:30) ● 休憩 (~13:30) ● 後半の部 ○ Deck Makerのブログ埋め込み機能を作ろう (~15:30)
Slide 3
Slide 3 text
自己紹介 ● 安藤真 (@andoshin11) ● 役職:テックリード ● 入社:2021年4月 ○ ex: LINE, メルカリ, Folio, 朝日新聞社, etc… ● 趣味:遊戯王(マスターデュエル), FPS, グルメ, ウィスキー ● 好きな技術:TS, Vue.js, Nuxt.js, k8s, Terraform, GO
Slide 4
Slide 4 text
01 02 モダンな技術を利用したプロダクト開発の楽しさを知ってもらう 本日のゴール 「トレカ × Tech」に挑戦する弊社について知ってもらう - 世間的にみても結構進んだ取り組みをしていると思う - あわよくば友人やネットでみなさんに宣伝して欲しい - Web Components(Lit) + TypeScript + Storybook - みなさんが実務でも利用できる部分があると嬉しいです
Slide 5
Slide 5 text
カーナベルを 支える技術
Slide 6
Slide 6 text
Deck Maker
Slide 7
Slide 7 text
Deck Maker コアとなる技術 1. 快適に利用できるSingle Page Application ○ 直感的にデッキ編集が行える UI設計 ○ 高速に仮説検証が行える改善基盤 2. 業界一のカード検索・デッキ検索機能 (自社調べ) ○ 数百万デッキに対して 2~300msで複合検索可能な検索バックエンド ○ ECサイトならではの価格データ連携
Slide 8
Slide 8 text
Deck Maker コアとなる技術 1. 快適に利用できるSingle Page Application ○ 直感的にデッキ編集が行える UI設計 ○ 高速に仮説検証が行える改善基盤 2. 業界一のカード検索・デッキ検索機能 (自社調べ) ○ 数百万デッキに対して 2~300msで複合検索可能な検索バックエンド ○ ECサイトならではの価格データ連携
Slide 9
Slide 9 text
No content
Slide 10
Slide 10 text
What’s good? ● Vue.js向けのフルスタックフレームワーク ○ Dynamic Routing, Server API, Build Optimization, Middleware, etc… ○ 充実したModule ecosystem ■ 弊社ではSentry, Google Analytics等のModuleを利用 ○ Webアプリケーション開発に必要なことを「大体なんでも」やってくれる ○ Pluginをうまく活用すればDIもサクッとできてテスタビリティが高い
Slide 11
Slide 11 text
Deck Maker コアとなる技術 1. 快適に利用できるSingle Page Application ○ 直感的にデッキ編集が行える UI設計 ○ 高速に仮説検証が行える改善基盤 2. 業界一のカード検索・デッキ検索機能 (自社調べ) ○ 数百万デッキに対して 2~300msで複合検索可能な検索バックエンド ○ ECサイトならではの価格データ連携
Slide 12
Slide 12 text
No content
Slide 13
Slide 13 text
What’s good? ● ドキュメント格納型の検索エンジン。とにかく速い & 高機能 ● RESTFul APIによりクライアント(Browser)から複雑なクエリを組み立てて検索を実行 できるためデッキメーカーと相性が良い ● 実際のクエリ利用例 ○ レベル7魔法使い族効果モンスターで破壊以外の除去効果を持つカード ○ フェアリー・ライフとフェアリー・ Re:ライフを含む水・自然文明のみかつ 5,000円以 下のデッキ ○ 等々
Slide 14
Slide 14 text
Architecture
Slide 15
Slide 15 text
Deck Maker (Nuxt.js) Firestore Firebase Functions カーナベルECサイト Elasticsearch 1. カード・デッキ検索 2. デッキを保存 3. 関数をトリガー 4. 価格データを取得 5. 正規化したデッキ データをWrite ※ 実際のアーキテクチャとは異なります
Slide 16
Slide 16 text
ECサイトリニューアル(WIP)
Slide 17
Slide 17 text
ECサイトリニューアル(WIP) ● 現行EC老朽化と事業拡大に対応するべく式年遷宮中 ● Microservices分割(とはいえ細かく分けすぎないように ) ○ 販売サイト ○ 買取サイト ○ トレカデータサービス ○ お客様情報管理サービス ○ 社員管理サービス ○ 認証基盤 ○ etc… ● 「難しいことを難しくやらない」という姿勢で適切に先端技術を取り込んでいく
Slide 18
Slide 18 text
Browser Frontend (Next.js) Contour (Envoy) Auth Gateway Argo CD・ Workflows Cilium OTel Collector Microservice A Microservice B Microservice C
Slide 19
Slide 19 text
Kubernetes ● Kubernetes自体は4年ほど前から利用中。 GKE(画像AI学習基盤) & EKS(新EC) ● Middlewareをサクッと導入しやすいのが便利 ○ Helm chart repositoryを用意してMiddleware versionsをgit管理 ● 何かあった時にソースコードレベルで原因調査を行える安心感 ≠ ブラックボックス ● Terraform Moduleを適切に設計すれば multi-cluster構成も導入しやすい ○ Middlewareの破壊的変更などを検証する際は clusterごと壊したり作り直したくなる ことが結構ある ○ multi-clusterであればcluster-levelの変更をユーザー影響なく検証できる ○ 現在はmain-cluster, experimental-clusterのdual構成で常時稼働中。一方に変 更を加えて動作確認が完了した段階で ALBの向き先を切り替える運用 ○ 徹底的にstatelessなclusterになるように意識している
Slide 20
Slide 20 text
Knative ● Cloud Runのようなzero-scalingやeventingをEKSでも行いたくて導入 ● EKSはNodeの稼働時間に応じて課金されるため、業務時間外の Staging Cluster費用が 勿体無い → Knativeならリクエストを送るまで Pod数を0にできて経済的 ● まだまだ導入企業は少ないものの、小さい開発組織とは相性が良さそう ● 余談: カーナベルは日本の会社として唯一 Knative Adoptersにリスティングされてる
Slide 21
Slide 21 text
Cilium ● eBPFで動作するネットワーク制御ツール ● Observability ○ カーネルレベルでCluster内の通信を追えるため、ネットワーク流量や経路の監視が 行いやすい ○ HubbleというIstioでいうKiali的なService Map可視化ツールもある ● Security ○ Namespace単位でNetwork Policyを定義でき、Cluster外へのアクセスを制御で きる ○ アクセス可能な外部サービス (決済プロバイダー, Firebase, Aurora, etc…)をホワ イトリストで定義し、万が一サーバーに侵入されても攻撃者のサーバーへデータを持 ち逃げされないよう制御
Slide 22
Slide 22 text
Q&A
Slide 23
Slide 23 text
Hands-on Web Components(Lit)を利用したモダンなUI開発体験
Slide 24
Slide 24 text
もう少しだけ座学にお付き合いください
Slide 25
Slide 25 text
そもそもWeb Componentsって何? ● 再利用可能なコンポーネントを独自の HTML Tags(Custom Elements)として定義するWebの標 準仕様 ● 2011年頃に初めて提唱され、Google主導のPolymer Projectなどを経て2016年頃から順次ブラ ウザ実装が進む。2020年以降は全てのモダンブラウザで利用可能 ● React / Vue / Angular / Svelteといったフレームワークに依存しない = ブラウザネイティブのラン タイムで動作。ポータビリティの高いコンポーネント 定義が可能に ● 実際は... ○ Web標準として汎用性重視の仕様となったため重厚な書き味に ... ○ LitやSvelte等で定義したコードをcompileして利用するケースが大半
Slide 26
Slide 26 text
Web Componentsを構成する要素 ● Custom Elements ○ 開発者が独自のHTML Tagsを定義し、挙動をカスタマイズできる ● Shadow DOM ○ Document APIやCSSの適用対象を特定のスコープ (Shadow DOM)に限定することが可 能になる。各コンポーネントの CSS定義が他の定義と干渉しない! ● HTML Template ○ というフラグメント要素(ページ読み込み時に描画されない DOM要素)の活用 ● ES Modules
Slide 27
Slide 27 text
Web Components in real-life
Slide 28
Slide 28 text
youtube.com
Slide 29
Slide 29 text
Material Web
Slide 30
Slide 30 text
Adobe Spectrum
Slide 31
Slide 31 text
How to use them?
Slide 32
Slide 32 text
CodeSandbox Link
Slide 33
Slide 33 text
Writing Web Components
Slide 34
Slide 34 text
CodeSandbox Link
Slide 35
Slide 35 text
CodeSandbox Link 1. HTMLElementを拡張してカ スタムクラスを定義
Slide 36
Slide 36 text
CodeSandbox Link 1. HTMLElementを拡張してカ スタムクラスを定義 2. shadowRootにHTMLを描 画。getAttributeで親要素から 渡された値を参照
Slide 37
Slide 37 text
CodeSandbox Link 1. HTMLElementを拡張してカ スタムクラスを定義 2. shadowRootにHTMLを描 画。getAttributeで親要素から 渡された値を参照 3. customElements.defineで カスタムタグを定義
Slide 38
Slide 38 text
CodeSandbox Link 1. HTMLElementを拡張してカ スタムクラスを定義 2. shadowRootにHTMLを描 画。getAttributeで親要素から 渡された値を参照 3. customElements.defineで カスタムタグを定義 4. 定義したカスタムタグを呼び 出し。Attributeで任意の値を指 定
Slide 39
Slide 39 text
Web Components Data-flow Parent Component Child Component Attributeを経由して値を伝達 CustomEventをdispatchEvent()で発火
Slide 40
Slide 40 text
Timer Componentを作ろう
Slide 41
Slide 41 text
Timer Componentを作ろう
Slide 42
Slide 42 text
Timer Componentを作ろう ① ● src/timer.ts を作成 ● index.htmlの
Slide 43
Slide 43 text
Timer Componentを作ろう ② ● HTMLElementを拡張して TimerComponentを定義 ● Shadow DOMやattribute監視の設定を 諸々追加 ● connectedCallbackに初期化処理を記 述 ● customElements.defineを呼んで というカスタムタ グを定義
Slide 44
Slide 44 text
Timer Componentを作ろう ②
Slide 45
Slide 45 text
Timer Componentを作ろう ③ ● timer private propertyを定義 ● startTimer() ○ setIntervalで1000ms = 1sご とにHTMLを書き換える ○ タイマーが終了したら timer-finishedイベントを発火 ● stopTimer() ○ タイマーを初期化する
Slide 46
Slide 46 text
Timer Componentを作ろう ④ ● Event Listenerの設定 ● connectedCallback() ○ 読み込み時の初期化処理 ● disconnectedCallback() ○ オフロード時のリセット処理 ○ メモリリークの防止 ● アロー関数におけるthisのスコープに注 意
Slide 47
Slide 47 text
Timer Componentを作ろう ⑤ ● 呼び出し元でtimer-finishedのイベン トリスナーを定義
Slide 48
Slide 48 text
Timer Componentを作ろう Check full code in Gist
Slide 49
Slide 49 text
正直、仕事で使うには辛い・・・ ● 現代のUIコンポーネント開発に必須な機能 ○ Reactに代表される宣言的テンプレート定義 ○ Vueに代表されるリアクティブなデータバインディング
Slide 50
Slide 50 text
正直、仕事で使うには辛い・・・ ● 現代のUIコンポーネント開発に必須な機能 ○ Reactに代表される宣言的テンプレート定義 ○ Vueに代表されるリアクティブなデータバインディング ● どちらも自前で実装する必要がある 🔥
Slide 51
Slide 51 text
正直、仕事で使うには辛い・・・ ● 現代のUIコンポーネント開発に必須な機能 ○ Reactに代表される宣言的テンプレート定義 ○ Vueに代表されるリアクティブなデータバインディング ● どちらも自前で実装する必要がある 🔥 ● 手続き的なDOM管理 ○ element.innerHTMLで一括更新を行うためパフォーマンスも悪い ● リアクティビティの担保とデータバインディング ○ class propertyにtemplateが依存した状態でpropertyが更新された場合、明示的に DOM の更新や参照部分の再計算を行う必要がある → 依存ツリーやbatch update queueの自 前管理が必要
Slide 52
Slide 52 text
No content
Slide 53
Slide 53 text
Lit: Simple. Fast. Web Components. ● Googleの開発者主導のプロジェクト。 Polymer Projectの後継 ● Web Componentsをより宣言的かつ生産的に開発するためのフレームワーク ● コンパイル後はネイティブの Web Componentsに変換されるため再利用性が高い ● Decorator(ref: TC39)を利用してreactive propertyを定義し、更新時にはbatch処理により影響 部分のみをatomicに更新してくれる = ハイパフォーマンス ● その他の便利な機能 ○ html関数や css関数とtagged template literalを組み合わせて安全なtemplateを記述 可能 = sanitize & virtual-node-treeの構築 ○ Pre-definedなdirectiveを活用して記述量を削減できる ○ TypeScript support
Slide 54
Slide 54 text
Lit Sandbox Link
Slide 55
Slide 55 text
LitでTimer Componentを作ろう litをインストール
Slide 56
Slide 56 text
LitでTimer Componentを作ろう tsconfig.jsonにオプションを追加
Slide 57
Slide 57 text
LitでTimer Componentを作ろう ① ● src/lit-timer.ts を作成 ● index.htmlの
Slide 58
Slide 58 text
LitでTimer Componentを作ろう ② ● LitElementを拡張する ● @customElement decoratorでラップ ● 親から受け取るdurationに@property decoratorを付与 ● render() ○ reactive propertyの変更に応じ て自動で実行される描画処理 ○ html関数にtagged template literalを渡して宣言的に定義
Slide 59
Slide 59 text
LitでTimer Componentを作ろう ③ ● timer private propertyを定義 ● startTimer() ○ setIntervalでduration propertyを更新。HTMLの書き換え は行わない ○ タイマーが終了したら timer-finishedイベントを発火 ● stopTimer() ○ タイマーを初期化する
Slide 60
Slide 60 text
LitでTimer Componentを作ろう ④ ● Event Listenerの設定 ● @click ○ onClickの糖衣構文 ○ template内で直接 addEventListener相当の処理を定義 可能 = 宣言的定義 ○ removeEventListenerも不要
Slide 61
Slide 61 text
LitでTimer Componentを作ろう ⑤ ● 呼び出し元でtimer-finishedのイベン トリスナーを定義
Slide 62
Slide 62 text
Lit Timer Componentを作ろう Check full code in Gist
Slide 63
Slide 63 text
No content
Slide 64
Slide 64 text
ここまでのまとめ
Slide 65
Slide 65 text
前半の部 まとめ ● Web Componentsを利用することで汎用的なカスタムタグを利用することができる ● Litを利用することでより宣言的かつ生産的なコンポーネント開発が行える ○ reactive property ○ declarative render function ○ etc… ● 後半の部ではLitを利用してDeck Makerのデッキ埋め込み機能を作っていきます
Slide 66
Slide 66 text
休憩時間 (~13:30)
Slide 67
Slide 67 text
後半の部: デッキ埋め込み機能を作ってみよう
Slide 68
Slide 68 text
完成イメージ Storybook Link
Slide 69
Slide 69 text
作業の流れ GitHub Repository
Slide 70
Slide 70 text
お題①: DMDeckInfo ● デッキの基本情報を表示するコンポーネントを作る (完成系) ● デザインは雰囲気で。paddingや細かいfont-sizeは特に指定しません ● property: ○ deckData ← APIから取得するデッキデータ。今回は mock値で代用 ● 表示する情報: ○ サムネイル ○ レギュレーション ○ 更新日 ○ デッキ名 ○ ユーザー名 ○ 閲覧数 レギュレーションの表示ルール ● none → 殿堂ゼロ ● advance → アドバンス ● 2block → 2ブロック ● party → デュエパーティー ● Original → オリジナル
Slide 71
Slide 71 text
お題②: DMTabs ● デッキの表示領域を切り替えるコンポーネントを作る (完成系) ● property: ○ deckData ← APIから取得するデッキデータ。今回は mock値で代用 ○ currentTab ← 現在表示中のタブ ● dispatchEvent: ○ change ← タブが選択されたら発火 ■ new CustomEvent(‘change’, { detail: targetTab }) ● その他仕様: ○ currentTabはactive classを付与 ○ メイン/GR/超次元はラベルの横に枚数を表示する ○ deckData.dorumagedonがtrueの時のみドルマゲドンのタブを表示する ○ deckData.zeronがtrueの時のみ零龍のタブを表示する
Slide 72
Slide 72 text
お題③: DMDeck ● 実際にサイトから呼び出されるデッキ取得 & 表示コンポーネント(完成系) ● property: ○ dmDeckId ← デュエマデッキID ● state: ○ currentTab ← 現在表示中のタブ ○ 参考: Lit - Internal reactive state ● methods ○ changeTab ← DMTabsコンポーネントのchange eventをトリガーに実行。受け取った値 でstateを更新する ● おまけ ○ Storybook上でdmDeckIdを変更た際にデッキの再取得 & 再描画を行うには? ○ 参考: Lit - Reactive update cycle
Slide 73
Slide 73 text
自サイトへの埋め込み方法
Slide 74
Slide 74 text
自サイトへの埋め込み方法
Slide 75
Slide 75 text
自サイトへの埋め込み方法 ● vite buildが実行されるとdist/assets/index-.jsが生成される ● 上記のindex.jsをサイトに読みこんで を呼ぶだけ ● --assetsInlineLimitで指定のbyte数以下の画像ファイルはインライン化できる
Slide 76
Slide 76 text
外部サイトへの埋め込み方法
Slide 77
Slide 77 text
外部サイトへの埋め込み方法 ● 外部のサービスプロバイダ (note, アメーバブログ, はてなブログ, etc…)がの仕様 を把握するのは流石にムリ ● デッキメーカーのnote埋め込み機能はどのように実装されているのか?
Slide 78
Slide 78 text
oEmbed ● oembed.comで定義されている汎用的なコンテンツ埋め込み仕様 ● 2008年ごろに提案され、Wordpressをはじめとする複数企業によってメンテナンス中 ● 埋め込み可能なコンテンツ : ○ photo ○ video ○ link ○ rich ← htmlの埋め込みが可能。Deck Maker(ガチまとめ)はこれを利用している
Slide 79
Slide 79 text
oEmbedのフロー 1. 埋め込みURLへアクセス
Slide 80
Slide 80 text
oEmbedのフロー
Slide 81
Slide 81 text
oEmbedのフロー 1. 埋め込みURLへアクセス 2. embed endpointをheadで伝達
Slide 82
Slide 82 text
oEmbedのフロー
Slide 83
Slide 83 text
oEmbedのフロー 1. 埋め込みURLへアクセス 2. embed endpointをheadで伝達 3. embed endpointへアクセス 4. Rich TypeのJSONを返却
Slide 84
Slide 84 text
oEmbedのフロー embed.json
Slide 85
Slide 85 text
oEmbedのフロー 1. 埋め込みURLへアクセス 2. embed endpointをheadで伝達 3. embed endpointへアクセス 4. Rich TypeのJSONを返却 5. JSONに指定されたiframeを描画 6. iframe srcで指定されたHTMLを返却
Slide 86
Slide 86 text
oEmbedのフロー iframe src link
Slide 87
Slide 87 text
本日はここまで
Slide 88
Slide 88 text
長時間お付き合いいただき ありがとうございました!