Upgrade to Pro — share decks privately, control downloads, hide ads and more …

固有技術の掛け算で事業推進に繋げるプロダクト開発

PLAID Tech
February 27, 2025

 固有技術の掛け算で事業推進に繋げるプロダクト開発

2025年2月27日開催
Web技術をどう活かす? 技術をプロダクト・事業の成長につなげるエンジニアの考え方
https://plaidtech.connpass.com/event/343681/

PLAID Tech

February 27, 2025
Tweet

More Decks by PLAID Tech

Other Decks in Technology

Transcript

  1. © PLAID, Inc. | Confidential Stats of KARTE © PLAID, Inc. | Confidential 4

    データ規模も爆発的に増加 199 億UU 累計ユーザー数 ※1 0.x 秒/解析 解析速度 134,000 over 秒間トラッキング数 ※3 2.59 兆円 年間解析流通⾦額 ※2 ※1 ローンチ〜2023年2⽉までのユニークユーザー数の実績 ※2 EC領域における解析流通⾦額。2022年3⽉〜2023年2⽉までの単年の実績 ※3 閲覧、クリック、購⼊などKARTEで計測しているユーザーの全イベントが 対象。ローンチ〜2023年3⽉までにおける最⼤値
  2. © PLAID, Inc. | Confidential プレイドの全体戦略 ユーザー軸によるリアルタイムのデータ可視化 / ア クションを強みとするKARTEの提供を通じて、オ ンサイトマーケティング領域より事業を開始 以降、カスタマーサポートやリサーチ等、各領域

    に最適化したプロダクト / サービスの提供によって マルチチャネルを形成 ”マルチチャネル × 1st Party Customer Data × リ アルタイム” をワンストップで提供するプラット フォーム実現に向けた基盤が構築されつつある © PLAID, Inc. | Confidential 5 1st Party Customer Data 戦略策定/ 事業‧組織開発 広告 市場調査/ 顧客調査 カスタマーサポート マーケティングオートメーション オフライン/OMO オンサイト マーケティング EmotionTech CX/EX KARTE Signals Databeat KARTE RightSupport STUDIO ZERO KARTE Message KARTE TALK KARTE Web/App KARTE Blocks
  3. © PLAID, Inc. | Confidential 本⽇のアジェンダ 1. はじめに 2. KARTE Blocks プロダクトについて

    3. KARTE Blocks を取り巻く  事業環境と戦略 4. ダイナミックブロックとは 5. ダイナミックブロックを   構成する技術要素 6. さいごに © PLAID, Inc. | Confidential 6
  4. © PLAID, Inc. | Confidential はじめに © PLAID, Inc. | Confidential 7 • 技術的なコアコンピタンスの掛け合わせによって

    • 他社がキャッチアップしづらい価値ある機能を⽣み出し • 強⼒に事業を推進することができる💡 本⽇お伝えしたいこと💬
  5. © PLAID, Inc. | Confidential 本⽇のアジェンダ 1. はじめに 2. KARTE Blocks プロダクトについて

    3. KARTE Blocks を取り巻く  事業環境と戦略 4. ダイナミックブロックとは 5. ダイナミックブロックを   構成する技術要素 6. さいごに © PLAID, Inc. | Confidential 8
  6. © PLAID, Inc. | Confidential KARTE Blocks プロダクトについて © PLAID, Inc. | Confidential 9

    • サイト改善における悩みは様々 ◦ 「継続してできない」「安⼼してできない」「⾃由にできない」 • KARTE Blocksは、「サイト改修‧更新の効率化」「テストによる仮説検証やパーソナライズ」 「データによる課題発⾒」までをワンストップで実現 • サイト運営の複雑性を緩和‧解消し、安⼼‧⾃由に⾏えるようにするプロダクトです あなたのサイト改善 あっという間に。継続的に。
  7. © PLAID, Inc. | Confidential 本⽇のアジェンダ 1. はじめに 2. KARTE Blocks プロダクトについて

    3. KARTE Blocks を取り巻く  事業環境と戦略 4. ダイナミックブロックとは 5. ダイナミックブロックを   構成する技術要素 6. さいごに © PLAID, Inc. | Confidential 12
  8. © PLAID, Inc. | Confidential KARTE Blocks を取り巻く 事業環境と戦略 © PLAID, Inc. | Confidential

    13 KARTE Blocksはサイトの「更新‧管理」および「サイト改善」に対 する課題を持つユーザ層を想定したプロダクト。 この領域においては、既に多くのプレイヤーが存在します👀 • CMS(Headfull/Headless) • Web接客ツール • A/Bテストツール • LPO‧EFOツール • ユーザー分析ツール(n1) • ヒートマップ • etc...
  9. © PLAID, Inc. | Confidential KARTE Blocks を取り巻く 事業環境と戦略 © PLAID, Inc. | Confidential

    14 個々のツールとの機能⽐較に終始して機能開発を⾏っても、後発の KARTE Blocksが短期で優位性を獲得することは難しいです。 このような市場環境で戦うためには、明確な負け理由(PoF)を減らし つつも他社と差別化した独⾃の価値(PoD)によって競争優位を⽣み出 し、「Blocksでなければならない理由」を作ることが重要です🗝 出典: https://note.com/secky/n/nccc12ffd4083
  10. © PLAID, Inc. | Confidential コンセプト‧設計思想 による差別化 © PLAID, Inc. | Confidential サイト運営・改善の取り組みをワンストップで実現する ツールやプロダクト、あるいはデータの分断が、複雑性を生み

    出してしまっている。 ワンストップで施策実行から検証までの機能を提供すること で、その複雑性を取り払い、安心・安全にサイト運営を継続で きる状態を実現する。 15 KARTE Blocks を取り巻く 事業環境と戦略
  11. © PLAID, Inc. | Confidential © PLAID, Inc. | Confidential 16 KARTE Blocks を取り巻く

    事業環境と戦略 機能による差別化 • 自由で直感的なノーコードエディタ • 高度なパーソナライズ • 定量分析・定性分析それぞれからサイトの課題を 深掘り • etc…
  12. © PLAID, Inc. | Confidential 機能による差別化 © PLAID, Inc. | Confidential 17 KARTE Blocks

    を取り巻く 事業環境と戦略 • 自由で直感的なノーコードエディタ • 高度なパーソナライズ • 定量分析・定性分析それぞれからサイトの課題を 深掘り • etc… コンセプトによる差別化と⽐較すると競合にキャッチアップされやすい 群にすることで「Blocksでなければならない強烈な理由」に昇華する
  13. © PLAID, Inc. | Confidential 本⽇のアジェンダ 1. はじめに 2. KARTE Blocks プロダクトについて

    3. KARTE Blocks を取り巻く  事業環境と戦略 4. ダイナミックブロックとは 5. ダイナミックブロックを   構成する技術要素 6. さいごに © PLAID, Inc. | Confidential 19
  14. © PLAID, Inc. | Confidential ダイナミックブロックとは 元となるデータのアップデートに応じて 配信するコンテンツを⾃動更新。 ex )ランキング、新着商品など。 ユーザーの⾏動履歴や年齢‧性別などを元に、特定の条件で コンテンツを表⽰し、パーソナライズ。

    ex)類似商品‧広告バナーなど。 動的なコンテンツ配信をサポートすることによって、 より⼀層⾃由なサイト運営を実現 🎉 ダイナミックブロック © PLAID, Inc. | Confidential 20
  15. © PLAID, Inc. | Confidential ダイナミックブロックとは アーキテクチャ © PLAID, Inc. | Confidential 22 アクションテーブル

    ⾃社データ データの⾃動取り込み データ連携ジョブを設定 ブロックを編集‧保存 ‧ファイルアップロード ‧データ抽出条件設定 クライアントサイト Blocks 書き換えスクリプト (builder.js) 設定を元に配信 解析基盤(Blitz) KARTE 計測スクリプト
  16. © PLAID, Inc. | Confidential ダイナミックブロックとは アーキテクチャ © PLAID, Inc. | Confidential 23 アクションテーブル

    ⾃社データ データの⾃動取り込み データ連携ジョブを設定 ブロックを編集‧保存 ‧ファイルアップロード ‧データ抽出条件設定 クライアントサイト Blocks 書き換えスクリプト (builder.js) 解析基盤(Blitz) KARTE スクリプト ①サイトにアクセス ③KARTEスクリプトを配信 with ユーザ情報 ②閲覧イベントを トリガー KARTE 計測スクリプト 設定を元に配信
  17. © PLAID, Inc. | Confidential ダイナミックブロックとは アーキテクチャ © PLAID, Inc. | Confidential 24 アクションテーブル

    ⾃社データ データの⾃動取り込み データ連携ジョブを設定 ブロックを編集‧保存 ‧ファイルアップロード ‧データ抽出条件設定 クライアントサイト Blocks 書き換えスクリプト (builder.js) 解析基盤(Blitz) KARTE スクリプト ①サイトにアクセス ③KARTEスクリプトを配信 with ユーザ情報 ④ユーザ情報を利⽤して データをクエリ ⑤データを返却 ②閲覧イベントを トリガー KARTE 計測スクリプト 設定を元に配信
  18. © PLAID, Inc. | Confidential ダイナミックブロックとは アーキテクチャ © PLAID, Inc. | Confidential 25 アクションテーブル

    ⾃社データ データの⾃動取り込み データ連携ジョブを設定 ブロックを編集‧保存 ‧ファイルアップロード ‧データ抽出条件設定 クライアントサイト Blocks 書き換えスクリプト (builder.js) 解析基盤(Blitz) KARTE スクリプト ①サイトにアクセス ③KARTEスクリプトを配信 with ユーザ情報 ④ユーザ情報を利⽤して データをクエリ ⑤データを返却 ⑥ユーザ情報と データをセット ⑦動的コンテンツで 書き換え ②閲覧イベントを トリガー KARTE 計測スクリプト 設定を元に配信
  19. © PLAID, Inc. | Confidential ダイナミックブロックとは アーキテクチャ © PLAID, Inc. | Confidential 26 アクションテーブル

    ⾃社データ データの⾃動取り込み データ連携ジョブを設定 ブロックを編集‧保存 ‧ファイルアップロード ‧データ抽出条件設定 クライアントサイト Blocks 書き換えスクリプト (builder.js) 解析基盤(Blitz) KARTE スクリプト ①サイトにアクセス ③KARTEスクリプトを配信 with ユーザ情報 ④ユーザ情報を利⽤して データをクエリ ⑤データを返却 ⑥ユーザ情報と データをセット ⑦動的コンテンツで 書き換え ②閲覧イベントを トリガー KARTE 計測スクリプト 設定を元に配信
  20. © PLAID, Inc. | Confidential ダイナミックブロックとは ダイナミックブロック の強み💪 © PLAID, Inc. | Confidential 27

    • データを流し込むブロックを、ノーコードで直感 的に編集できる • アクセスユーザを解析基盤で瞬時に識別し、個⼈ に合わせた⾼度なパーソナライズを実現できる • データ連携の設定がGUIで完結する • データ抽出ロジックを⾃分たちの仮説に合わせて ⾃由にSQLレスで設定でき、検証できる
  21. © PLAID, Inc. | Confidential 本⽇のアジェンダ 1. はじめに 2. KARTE Blocks プロダクトについて

    3. KARTE Blocks を取り巻く  事業環境と戦略 4. ダイナミックブロックとは 5. ダイナミックブロックを   構成する技術要素 6. さいごに © PLAID, Inc. | Confidential 28
  22. © PLAID, Inc. | Confidential ダイナミックブロックを 構成する技術要素 ダイナミックブロックは、⼤きく4つのユニークな要素で成り⽴っ ている機能です。 本⽇は、特にその中からKARTE Blocksが有するサードパーティス クリプト「builder.js」の詳細についてご説明します。

    © PLAID, Inc. | Confidential 29 • 直感的なノーコードエディタ • 柔軟なサイト書き換えを実現する独⾃ サードパーティスクリプト builder.js👈 • リアルタイム解析基盤 Blitz • アクションテーブル
  23. © PLAID, Inc. | Confidential ダイナミックブロックを 構成する技術要素 builder.jsは「書き換えロジックのソース」 + 「各プロジェクトの設 定値」で構成されています。 KARTE

    Blocksでユーザが操作を保存すると、それが書き換えに関連 する内容である場合は、直ちに書き換え⽤のスクリプトが新たにビル ドされ、配信されます。 © PLAID, Inc. | Confidential 32 管理画⾯サーバ builder.js ビルドサーバ { … } 設定値をペイロードとして ビルドをトリガー 設定値を埋め込んで builder.jsを ビルド&アップロード 設定を保存 CDNを通じて builder.jsを配信 クライアントサイト 管理画⾯ builder.js クラウドストレージ 👈冗⻑化 👈冗⻑化
  24. © PLAID, Inc. | Confidential ダイナミックブロックを 構成する技術要素 builder.jsによる書き換えの仕組みは、極限まで単純化すると右記の ようなものです。 バンドルされた設定値に基づいて、セレクタで書き換え対象の要素を 取得して、書き換え後のHTMLで上書きするといったような処理を ⾏っています。

    © PLAID, Inc. | Confidential 33 // Blocksの設定の部分的な例 const CONFIG = [{ selector: 'body > img', html: '<img src="https://via.placeholder.com/150/0000FF/FFFFFF?text=New%20Image"/>' }]; // 書き換えロジック const rewrite = () => { CONFIG.forEach(({ selector, html }) => { const element = document.querySelector(selector); if (!element) return; element.outerHTML = html; }); }; const onReady = (callback) => { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { callback(); }); } else { callback(); } }; // main onReady(() => { rewrite(); });
  25. © PLAID, Inc. | Confidential ダイナミックブロックを 構成する技術要素 © PLAID, Inc. | Confidential 34 ダイナミックブロックの書き換え

    前⾴にて例⽰したように、通常の書き換えブロックに関する設定につ いては、通常のHTML形式で書き換え後の値が保存されていました。 では、動的にコンテンツを埋め込むダイナミックブロックではどのよ うにしているのでしょうか?
  26. © PLAID, Inc. | Confidential ダイナミックブロックを 構成する技術要素 ダイナミックブロックの書き換え 上が通常のHTMLデータサンプル、下がダイナミックブロックに対応し た書き換えHTMLデータ(ダイナミックブロックテンプレート)のサン プルです。 なんとなく、馴染みのある構⽂ではないでしょうか?

    © PLAID, Inc. | Confidential 35 <ul> <li> <a href="/blocks/items/details/denim-shirts.html"> <img src="/blocks/assets/images/item-01-thumb.png" alt=""> <figcaption> <strong>BRANDNAME</strong><br> ¥18,900 </figcaption> </a> </li> </ul> <ul> <li krt-for="item in data.items"> // krt-forで動的にli要素を生成 <a :href="item.link"> // href属性に変数を bind <img :src="item.image_url" alt=""> <figcaption> <strong>#{item.category}</strong><br> // マスタッシュ構文でテキスト展開 ¥#{item.price} </figcaption> </a> </li> </ul>
  27. © PLAID, Inc. | Confidential ダイナミックブロックを 構成する技術要素 © PLAID, Inc. | Confidential 36 <ul>

    <li> <a href="/blocks/items/details/denim-shirts.html"> <img src="/blocks/assets/images/item-01-thumb.png" alt=""> <figcaption> <strong>BRANDNAME</strong><br> ¥18,900 </figcaption> </a> </li> </ul> <ul> <li krt-for="item in data.items"> // krt-forで動的にli要素を生成 <a :href="item.link"> // href属性に変数を bind <img :src="item.image_url" alt=""> <figcaption> <strong>#{item.category}</strong><br> // マスタッシュ構文でテキスト展開 ¥#{item.price} </figcaption> </a> </li> </ul> ダイナミックブロックの書き換え 実は、ダイナミックブロックテンプレートは Petite-Vueというライ ブラリをベースに作っています。 Petite-VueはEvan Youによって開発された、軽量版 Vue.jsのようなラ イブラリです。
  28. © PLAID, Inc. | Confidential Why Petite-Vue ? © PLAID, Inc. | Confidential •

    データをUIに反映する際、HTMLを動的に書き換える仕組みが必要 • しかし、ノーコードでJavaScriptコードを生成・管理するのは難易度 が高いため、宣言的な記法でコンテンツ書き換えを実現したい • ランタイムサイズが軽量であること • HTML互換であること • JSX/TSXやSvelteの構文はこれに当てはまらない • ASTとして扱えること • 多くの人にとって馴染みがある記法 であること 37 ダイナミックブロックを 構成する技術要素
  29. © PLAID, Inc. | Confidential ダイナミックブロックを 構成する技術要素 ダイナミックブロックの書き換え 次に、ダイナミックテンプレートを利⽤したブロックの書き換え処理 をみていきます。 KARTE Blocksの書き換え処理は、チラつき(フリッカー現象)を防

    ⽌するために基本的に元ページの描画前に差し込んで同期的に実⾏さ れます。 ダイナミックブロックにおいても、まずは同期的な書き換えを⾏いま す。 つまり、書き換え対象の要素をセレクタで取得し、保存されたダイナ ミックブロックテンプレートで書き換えを⾏います。 © PLAID, Inc. | Confidential 38 const CONFIG = [{ selector: '#target', html: '<ul><li krt-for="item in data.items"><a :href="item.link"><img :src="item.image_url" alt=""><figcaption><strong>#{item.category}</strong><br> ¥#{item.price}</figcaption></a></li></ul>', variablesQueriy: [...] }];
  30. © PLAID, Inc. | Confidential ダイナミックブロックを 構成する技術要素 © PLAID, Inc. | Confidential 39 export

    function createPetiteVueDynamicRenderer({ selectors, PetiteVuePkg, }: { selectors: string[]; PetiteVuePkg: PetiteVue; }): DynamicRenderer { const rootElementsMap: Record<string, Element> = {}; const reactiveScopeValuesMap: Record<string, { _setData: any; _getData: any }> = {}; let app: PetiteVueApp | undefined; const render: DynamicRenderer['render'] = () => { const { createApp } = PetiteVuePkg; selectors.forEach(selector => { const element = document.querySelector(selector); if (element) { rootElementsMap[selector] = element; } }); Object.entries(rootElementsMap).forEach(([selector, element]) => { setAttributesForRender(element, selector); }); app = createApp({ Scope, $delimiters: ['#{', '}'], }); app.directive(EXPORT_DIRECTIVE_NAME, exportDirective).mount(); }; const setData: DynamicRenderer['setData'] = (selector, data) => { reactiveScopeValuesMap[selector]?._setData(data); }; const getData: DynamicRenderer['getData'] = selector => { return reactiveScopeValuesMap[selector]?._getData(); }; return { render, setData, getData }; } ダイナミックブロックの書き換え 次に、ダイナミックブロックのターゲットとなる要素全てに対してレンダリ ング⽤の前処理を⾏い、petite-vueのAppをbody要素にマウントします。 petite-vueは krt-scope というディレクティブが有効な要素をリアクティブ に管理します。
  31. © PLAID, Inc. | Confidential ダイナミックブロックを 構成する技術要素 © PLAID, Inc. | Confidential 40 export

    function createPetiteVueDynamicRenderer({ selectors, PetiteVuePkg, }: { selectors: string[]; PetiteVuePkg: PetiteVue; }): DynamicRenderer { const rootElementsMap: Record<string, Element> = {}; const reactiveScopeValuesMap: Record<string, { _setData: any; _getData: any }> = {}; let app: PetiteVueApp | undefined; const render: DynamicRenderer['render'] = () => { const { createApp } = PetiteVuePkg; selectors.forEach(selector => { const element = document.querySelector(selector); if (element) { rootElementsMap[selector] = element; } }); Object.entries(rootElementsMap).forEach(([selector, element]) => { setAttributesForRender(element, selector); }); app = createApp({ Scope, $delimiters: ['#{', '}'], }); app.directive(EXPORT_DIRECTIVE_NAME, exportDirective).mount(); }; const setData: DynamicRenderer['setData'] = (selector, data) => { reactiveScopeValuesMap[selector]?._setData(data); }; const getData: DynamicRenderer['getData'] = selector => { return reactiveScopeValuesMap[selector]?._getData(); }; return { render, setData, getData }; } ターゲットとなる要素に対してレンダリング⽤の属性を設定 各要素に対して、 krt-scope 属性と krt-_export 属性を設定。 petite-vueは、 krt-scope 属性が有効な要素に対してリアクティブな管理を ⾏います。 function setAttributesForRender(element: Element, selector: string) { element.setAttribute('krt-scope', `Scope('${selector}')`); element.setAttribute('krt-_export', '{ _getData, _setData, _selector }'); }
  32. © PLAID, Inc. | Confidential ダイナミックブロックを 構成する技術要素 © PLAID, Inc. | Confidential 41 export

    function createPetiteVueDynamicRenderer({ selectors, PetiteVuePkg, }: { selectors: string[]; PetiteVuePkg: PetiteVue; }): DynamicRenderer { const rootElementsMap: Record<string, Element> = {}; const reactiveScopeValuesMap: Record<string, { _setData: any; _getData: any }> = {}; let app: PetiteVueApp | undefined; const render: DynamicRenderer['render'] = () => { const { createApp } = PetiteVuePkg; selectors.forEach(selector => { const element = document.querySelector(selector); if (element) { rootElementsMap[selector] = element; } }); Object.entries(rootElementsMap).forEach(([selector, element]) => { setAttributesForRender(element, selector); }); app = createApp({ Scope, $delimiters: ['#{', '}'], }); app.directive(EXPORT_DIRECTIVE_NAME, exportDirective).mount(); }; const setData: DynamicRenderer['setData'] = (selector, data) => { reactiveScopeValuesMap[selector]?._setData(data); }; const getData: DynamicRenderer['getData'] = selector => { return reactiveScopeValuesMap[selector]?._getData(); }; return { render, setData, getData }; } Black65 function Scope(selector) { return { data: {}, _setData(newData) { this.data = newData; }, _getData() { return this.data; }, _selector: selector, }; } 要素ごとにデータを管理するオブジェクトを作成する関数の定義 Scope関数によって各要素のデータストアを定義しています。 要素のセレクタ、データ更新処理、データ取得処理が定義されています。
  33. © PLAID, Inc. | Confidential © PLAID, Inc. | Confidential 42 export function createPetiteVueDynamicRenderer({

    selectors, PetiteVuePkg, }: { selectors: string[]; PetiteVuePkg: PetiteVue; }): DynamicRenderer { const rootElementsMap: Record<string, Element> = {}; const reactiveScopeValuesMap: Record<string, { _setData: any; _getData: any }> = {}; let app: PetiteVueApp | undefined; const render: DynamicRenderer['render'] = () => { const { createApp } = PetiteVuePkg; selectors.forEach(selector => { const element = document.querySelector(selector); if (element) { rootElementsMap[selector] = element; } }); Object.entries(rootElementsMap).forEach(([selector, element]) => { setAttributesForRender(element, selector); }); app = createApp({ Scope, $delimiters: ['#{', '}'], }); app.directive(EXPORT_DIRECTIVE_NAME, exportDirective).mount(); }; const setData: DynamicRenderer['setData'] = (selector, data) => { reactiveScopeValuesMap[selector]?._setData(data); }; const getData: DynamicRenderer['getData'] = selector => { return reactiveScopeValuesMap[selector]?._getData(); }; return { render, setData, getData }; } カスタムディレクティブによるgetter/setterのブリッジ get(exp) はカスタムディレクティブの実装において、バインドされた値を評 価して返します。 _selector はターゲット要素のセレクタ、 _getData はデータプロパティの getter、 _setData はデータプロパティのsetterとそれぞれバインドされてい ます。 この処理で、 reactiveScopeValuesMap にgetter/setterをセレクタごとに保 存し、petite-vueの外部からデータ操作関数にアクセス可能にしています。 const exportDirective: PetiteVueDirective = ({ get, effect, exp }) => { effect(() => { const value = get(exp); const selector = value?._selector; if (selector) { reactiveScopeValuesMap[selector] = { _getData: value._getData, _setData: value._setData, }; } }); }; ダイナミックブロックを 構成する技術要素
  34. © PLAID, Inc. | Confidential ダイナミックブロックを 構成する技術要素 © PLAID, Inc. | Confidential 43 const

    CONFIG = [{ selector: '#target', html: '<ul><li krt-for="item in data.items"><a :href="item.link"><img :src="item.image_url" alt=""><figcaption><strong>#{item.category}</strong><br> ¥#{item.price}</figcaption></a></li></ul>', variablesQueriy: [...] }]; ☝ダイナミックブロックでは、 variablesQueryというプロパティが追加され、 そこにデータ取得⽤のクエリ定義が含まれている ダイナミックブロックの書き換え 次に、書き換え設定に保存されたクエリ定義にしたがって、それぞれ のダイナミックブロック描画に必要なデータの取得を⾮同期に⾏いま す。 データ取得に成功したら、リアクティブデータを更新し、再レンダリ ングを発⽕します。
  35. © PLAID, Inc. | Confidential ダイナミックブロックを 構成する技術要素 © PLAID, Inc. | Confidential 44 render(targets)

    { const selectors = targets.map(({ selector }) => selector); // 1⃣ Petite-Vue による Renderer のセットアップ const dynamicRenderer = createPetiteVueDynamicRenderer({ selectors, PetiteVuePkg: PetiteVue, }); renderState = { dynamicRenderer, targets }; dynamicRenderer.render(); // **同期レンダリング( Petite-Vue の適用)** // 2⃣ 各要素ごとにデータ取得 targets.forEach(async ({ variation, selector }) => { // **createSetDataByUpdater() を展開** const setDataByUpdater = (updater) => { dynamicRenderer.setData(selector, updater(dynamicRenderer.getData(selector))); }; dispatchEvent(variation.variationId, 'beforeDataLoad'); // `variablesQuery` の取得 const variablesQuery = variation.variablesQuery; if (!variablesQuery) return; try { // 3⃣ データ取得前に `loading` ステータスを適用 setDataByUpdater(prev => ({ ...prev, _loadingStatus: 'loading' })); // 4⃣ `variablesQuery` を解決 const resolvedVariables = await resolveVariablesQuery(variablesQuery); // 5⃣ データ適用後に `success` ステータスを更新 setDataByUpdater(prev => ({ ...prev, ...resolvedVariables, _loadingStatus: 'success' })); await dynamicRenderer.nextTick(); dispatchEvent(variation.variationId, 'dataLoaded'); } catch (e) { setDataByUpdater(prev => ({ ...prev, _loadingStatus: 'error' })); dispatchEvent(variation.variationId, 'error', { raw: e }); } }); } ダイナミックブロックの書き換え 次に、書き換え設定に保存されたクエリ定義にしたがって、それぞれ のダイナミックブロック描画に必要なデータの取得を⾮同期に⾏いま す。 データ取得に成功したら、リアクティブデータを更新し、再レンダリ ングを発⽕します。
  36. © PLAID, Inc. | Confidential おさらい © PLAID, Inc. | Confidential • ダイナミックブロックの書き換え設定はPetite-Vueベースの構文でテンプレートを作成 し、保存している

    • 書き換え処理は、⬇のような流れで行われる • セレクタで要素を取得し、同期的にダイナミックブロックテンプレートで書き換 え • 対象の要素にリアクティブ管理をするためのディレクティブを付与し、 Petite-Vueのアプリケーションをマウント • 書き換え設定に含まれるクエリ定義でデータの取得を非同期に行い、取得に 完了したらリアクティブデータを更新し再レンダリング 45 ダイナミックブロックを 構成する技術要素
  37. © PLAID, Inc. | Confidential 本⽇のアジェンダ 1. はじめに 2. KARTE Blocks プロダクトについて

    3. ダイナミックブロックとは 4. ダイナミックブロックを   構成する技術要素 5. KARTE Blocks を取り巻く  事業環境と戦略 6. さいごに © PLAID, Inc. | Confidential 46
  38. © PLAID, Inc. | Confidential 本⽇のまとめ © PLAID, Inc. | Confidential KARTE Blocks は、競合プレイヤーが多い領域で後発として奮闘している。

    そこで、“Blocksでなければならない理由 ”を生み出し、戦いの軸をずらす戦略をとって いる。 差別化の軸は、大きく コンセプト・設計レベル と 機能レベル に分けられる。 • コンセプト・設計レベルの差別化 は、競合がキャッチアップしづらく、長期的な 強みになりやすい。 • 機能レベルの差別化 は、模倣されやすいため、単体ではなく機能の群として 独自価値に昇華することが重要。 さらに、技術的固有価値を掛け合わせることで、キャッチアップしづらく、かつコンセプト にマッチした機能を生み出せば、強力な武器になる ⚔🔥 47 さいごに