BASEにおける Vueコンポーネント設計の現在
by
simezi9
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
© - BASE, Inc. BASEにおける Vueコンポーネント設計の現在
Slide 2
Slide 2 text
⾃⼰紹介 © - BASE, Inc. 松原 佑介 フロントエンドエンジニア 2018年9⽉BASE⼊社 : simezi
Slide 3
Slide 3 text
BASEのプロダクト © - BASE, Inc. ネットショップ作成サービス 「BASE」 ショッピングアプリ 「BASE」 Payment to the People, Power to the People MISSION
Slide 4
Slide 4 text
© - BASE, Inc. 2019年10⽉25⽇ マザーズ上場しました
Slide 5
Slide 5 text
BASEのフロントエンド開発の現状 © - BASE, Inc. サーバーサイド:PHP, Go フロントエンドエンジニア:6名 フロントエンド:Vue.js, TypeScript, Sketch デザイナー:8名 (2019年10⽉時点)
Slide 6
Slide 6 text
フロントエンドチームは何をしてきたか © - BASE, Inc. • 管理画⾯刷新プロジェクト開始で jQueryからVue.js+TS化 • SPAではなく、⼤きな機能単位で MPA(Multi Page Application)化 • 内製のUIコンポーネントライブラリ の作成 ࣍ͷ5Λࢧ͑ΔVue.jsUIίϯϙʔωϯτϥΠϒϥϦΛҭͯΔ
Slide 7
Slide 7 text
今ではプロジェクト開始から約1年半 © - BASE, Inc. 本⽇はそこで追加で得られた コンポーネントづくりの知⾒ について話します
Slide 8
Slide 8 text
おしながき © - BASE, Inc. BASEでのコンポーネント設計 Storybookの整備 個別のコンポーネントの実装
Slide 9
Slide 9 text
© - BASE, Inc. ①BASEでのコンポーネント設計
Slide 10
Slide 10 text
コンポーネントの種類 © - BASE, Inc. Atomic DesignとContainer Componentの考え⽅を 借りて、役割に応じて⼤きく4つに分類 . Container Component . Presentational Component . Common Presentational Component . Atom Component ( UIライブラリ )
Slide 11
Slide 11 text
コンポーネントの種類 © - BASE, Inc. コンポーネントを役割に応じて⼤きく4つに分類 . Container Component . Presentational Component . Common Presentational Component . Atom Component ( UIライブラリ )
Slide 12
Slide 12 text
Container Component © - BASE, Inc. • Atomic DesignでいうPageに相当 • API通信、Storeへのアクセスを⾏うことができる 唯⼀のコンポーネント • 複数のPresentational ComponentやContainer Componentを束ねる役割 • ContainerComponentの中に多少のUIを持つこと は認める
Slide 13
Slide 13 text
コンポーネントの種類 © - BASE, Inc. コンポーネントを役割に応じて⼤きく4つに分類 . Container Component . Presentational Component . Common Presentational Component . Atom Component ( UIライブラリ )
Slide 14
Slide 14 text
Presentational Component © - BASE, Inc. • Template/Organismに相当 • 副作⽤を持たず、与えられたプロパティを表⽰するだ けのコンポーネント • 具体的なビジネスロジック‧表現に紐づくため再利⽤ 性は考えないコンポーネント • ContainerComponentと PresentationalComponentはディレクトリを分け ず、名前で区別する
Slide 15
Slide 15 text
コンポーネントの種類 © - BASE, Inc. コンポーネントを役割に応じて⼤きく4つに分類 . Container Component . Presentational Component . Common Presentational Component . Atom Component ( UIライブラリ )
Slide 16
Slide 16 text
Common Presentational Component © - BASE, Inc. • Template / Organism / Moleculeに相当 • Presentational Componentの中でアプリケーション の内部で頻出するデザインのパターンを定義する • 例)全体のヘッダーやページのパンくずとタイトル • 具体的なコンテキストがない抽象的で使い回しができ るコンポーネント群
Slide 17
Slide 17 text
コンポーネントの種類 © - BASE, Inc. コンポーネントを役割に応じて⼤きく4つに分類 . Container Component . Presentational Component . Common Presentational Component . Atom Component ( UIライブラリ )
Slide 18
Slide 18 text
Atom Component © - BASE, Inc. • Atomic DesignでいうMolecule/Atomに相当 • 個別のアプリケーションにとどまらず、サービス全体 で流⽤できるような⼩さいコンポーネント群 • form部品やbuttonなどの利⽤頻度がたかいもの • スタイルの局所的な上書きも許容できるように Scoped CSS / CSS Modulesを使わない • コンポーネント外との関係を決めるスタイルは当てな い 例) margin, float, z-index‧‧‧etc
Slide 19
Slide 19 text
概念図 © - BASE, Inc.
Slide 20
Slide 20 text
概念図 © - BASE, Inc. ΠϕϯτͷྲྀΕ
Slide 21
Slide 21 text
概念図 © - BASE, Inc. ֎෦ͱͷ௨৴ Container͚ͩͰߦ͏
Slide 22
Slide 22 text
概念図 © - BASE, Inc. Common/Presentational ͲͪΒͰʹͳΕΔ
Slide 23
Slide 23 text
© - BASE, Inc. ②Storybookの扱い
Slide 24
Slide 24 text
Storybookに求められる2つの役割 © - BASE, Inc. .サンドボックス 実際のコードに対してどう動くかを試す環境 実装の際のエンジニア向けガイドとしての働き .カタログ 提供されているコンポーネントを網羅的に⾒る どちらかの要素が⽋けたものが出来上がりがち
Slide 25
Slide 25 text
サンドボックス性の⾜りないStorybook © - BASE, Inc. 昔ながらのUIカタログの機能しかないケース • やりたいことはわかっても渡すべきprops、 キャッチすべきevent、他コンポーネントと の組み合わせなど、実装に必要な情報が⾜ りない • storybookに置く意味があまりない • 実装を意識しないならsketch上にあるだけ でいい
Slide 26
Slide 26 text
カタログ性の⾜りないStorybook © - BASE, Inc. 実装者が作るだけ作って満⾜してしまった ケース • コンポーネントが⼀個おいてあるだけ 想定されている使い⽅が伝わらない • knobsに⼤量のパラメータ パラメータの組み合わせもわからず、作った ⼈にしかわからない。特にデザイナーとはコ ミュニケーションが難しい 協業の場として機能しない
Slide 27
Slide 27 text
storybookを機能させるために © - BASE, Inc. • Knobsに頼りすぎない • あくまでknobsは補助 • UIとして利⽤するパターンはなるべく⼀覧できる ように(= カタログ) • 実装に必要な情報はきちんと書く(=サンドボックス) • コンポーネントごとにREADME.mdを⽤意する
Slide 28
Slide 28 text
コンポーネントごとのREADME.md © - BASE, Inc. @storybook/addon-notesで読み込む 必要な情報 • 簡単なサンプルコード • 動作の仕様 • Propsの値、型、デフォルト値 • Eventの発⽕タイミング、payload • slotの名前 • scoped-slotで渡される値 …etc 将来的には@storybook/addon-docsで markdownを活⽤できるようになるはず (現在はVueのサポートがWIP)
Slide 29
Slide 29 text
コンポーネントのレイヤ別に必要なこと © - BASE, Inc. ίϯϙʔωϯτͷछྨ Χλϩάੑ αϯυϘοΫεੑ Container Storybook্ʹ ొ͠ͳ͍ Presentational Common ߴ Atom ߴ ߴ レイヤの低い抽象的なコンポーネントほど説明が必要
Slide 30
Slide 30 text
© - BASE, Inc. ③個別のコンポーネントの実装
Slide 31
Slide 31 text
フロントエンドの性質 © - BASE, Inc. • フロントエンドのコードはライフサイクルが短い • 修正=全取替であることが珍しくない • ドメインロジックに落としづらい細かい分岐の連続 • 例)ある⼀箇所だけ「0円」を「無料」にしたい… • 共通化しても仕様がすぐに変わってしまう
Slide 32
Slide 32 text
© - BASE, Inc. コンポーネントで作る最⼤の メリットは共通化ではなく 責務の分離
Slide 33
Slide 33 text
コンポーネントの責務の分離 © - BASE, Inc. • コンポーネントで作ることでスタイル、マークアッ プ、スクリプトを外部に影響しない形でカプセル化 できる • 作る側もとにかく疎結合を優先して、類似コードの 重複を恐れない。 • 本当に必要なパターンと確定したら共通化する • いつでもコードの塊で捨てられる状態をキープする
Slide 34
Slide 34 text
実装のtips① props © - BASE, Inc. • ObjectやArrayを型に指定するのはなるべく避ける 特にTSを採⽤している場合にはPropTypeを使う props: { deliveryInfo: { type : Array as PropType }, payment: { type : String as PropType, } },
Slide 35
Slide 35 text
実装のtips① props © - BASE, Inc. • HTML標準に沿った名前、汎⽤的な名前をつかう ίϯϙʔωϯτར༻ऀ͔ΒΈͨࣗવͳΠϯλʔϑΣΠεΛ৺͕͚Δ name: 'AppInput', props: { id: String, name: String, type: String, value: { default: '', type: [String, Number], }, placeholder: String, }
Slide 36
Slide 36 text
実装のtips②event © - BASE, Inc. • イベント名にカラフルな語彙を使わない BASEͰ {Πϕϯτͷಈࢺ}:{Πϕϯτͷର} ͱ͍͏ϑΥʔϚοτΛར༻͍ͯ͠Δ ྫ) update:someValue • XMLͷ໊લۭؒͷϑΥʔϚοτʹ߹Θͤͯಈࢺ+(͋Εతޠ)ͷܗࣜ • ಈࢺͷޠኮΛߜΓγϯϓϧͳ୯ޠΛ͏͜ͱͰݟ௨͕͕͋͠Δ • ಛʹಈࢺίϯϙʔωϯτʹ ͨ͠Πϕϯτ໊Λ͚ͭͳ͍
Slide 37
Slide 37 text
実装のtips②event © - BASE, Inc. • イベントのpayloadにObjectを使う • RORO(Receive an object, return an object) • emitするプロパティが増えても壊れにくい // emit͢Δଆ this.$emit('change', { enabled: defaults, dirty: false }) // ड͚औΔଆɹ updateShippingFee({ enabled, dirty }) { // ObjectͷׂೖͰड͚औΔ this.$store.useCase(new EditItemDetail()).updateShippingFee(enabled, dirty) }
Slide 38
Slide 38 text
実装のtips③style © - BASE, Inc. • classを条件分岐や処理で渋滞させない • すべてclassで表現するとパターンが増えたときに 爆発しがち // Մಡੑͷ͍ίʔυ
Slide 39
Slide 39 text
実装のtips③style © - BASE, Inc. • ⼀時的な状態に依存するスタイルはdata-*やaria-* と属性セレクタの組み合わせで当てる • 例) ローディング中、選択中か、など .foo { &[aria-selected="true"] { color: $green; } &[aria-selected="false"] { color: $gray; } }
Slide 40
Slide 40 text
実装のtips④scoped-slot © - BASE, Inc. コンポーネントの内部状態を⼀元管理するコンポー ネントが欲しくなる場合にはscoped-slotを利⽤す る 例) • テーブルのヘッダとリストの結びつき管理 • モーダルのトリガとなるコンポーネントとモー ダルのコンテンツ
Slide 41
Slide 41 text
実装のtips④scoped-slot © - BASE, Inc. モーダルのサンプル දࣔ͢Δ
ίϯςϯπ
Slide 42
Slide 42 text
まとめ © - BASE, Inc. • コンポーネントでいちばん⼤事なのは責務の分離 • 特にContainerとPresentationalなコンポーネン トの役割わけをきっちり守るのは重要 • いつでもコード(特にUI側)を捨てられるように。 • Storybookには広い利⽤者に向けたおもてなしの⼼ が必要 • ちょっとした⾶び道具的な修正でコンポーネントの前提が壊れても泣かない
Slide 43
Slide 43 text
© - BASE, Inc. ありがとうございました