Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
BASEにおける Vueコンポーネント設計の現在
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
simezi9
October 30, 2019
Programming
13
51k
BASEにおける Vueコンポーネント設計の現在
Vue.jsアーキテクチャリング勉強会
https://cw-engineers.connpass.com/event/146975/
で話したスライドです
simezi9
October 30, 2019
Tweet
Share
More Decks by simezi9
See All by simezi9
次の5年を支えるVue.js製UIコンポーネントライブラリを育てる / build up Vue.js component library for next five years.pdf
simezi9
7
5.4k
VBScript meets Vue.js 〜20年越しの出会い〜
simezi9
9
1.8k
Other Decks in Programming
See All in Programming
Go 1.26でのsliceのメモリアロケーション最適化 / Go 1.26 リリースパーティ #go126party
mazrean
1
400
オブザーバビリティ駆動開発って実際どうなの?
yohfee
3
850
Codexに役割を持たせる 他のAIエージェントと組み合わせる実務Tips
o8n
4
1.3k
Cyrius ーLinux非依存にコンテナをネイティブ実行する専用OSー
n4mlz
0
150
技術検証結果の整理と解析をAIに任せよう!
keisukeikeda
0
120
どんと来い、データベース信頼性エンジニアリング / Introduction to DBRE
nnaka2992
1
290
AI時代のシステム設計:ドメインモデルで変更しやすさを守る設計戦略
masuda220
PRO
5
1k
GoのDB アクセスにおける 「型安全」と「柔軟性」の両立 - Bob という選択肢
tak848
0
110
ロボットのための工場に灯りは要らない
watany
10
2.9k
ふつうのRubyist、ちいさなデバイス、大きな一年 / Ordinary Rubyists, Tiny Devices, Big Year
chobishiba
1
460
Go Conference mini in Sendai 2026 : Goに新機能を提案し実装されるまでのフロー徹底解説
yamatoya
0
600
モックわからないマン卒業記 ~振る舞いを起点に見直した、フロントエンドテストにおけるモックの使いどころ~
tasukuwatanabe
2
380
Featured
See All Featured
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.5k
Ethics towards AI in product and experience design
skipperchong
2
220
A designer walks into a library…
pauljervisheath
210
24k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
1.7k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
140
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
1
160
ラッコキーワード サービス紹介資料
rakko
1
2.6M
The agentic SEO stack - context over prompts
schlessera
0
700
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.1k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
5
770
The browser strikes back
jonoalderson
0
800
Designing for Performance
lara
611
70k
Transcript
© - BASE, Inc. BASEにおける Vueコンポーネント設計の現在
⾃⼰紹介 © - BASE, Inc. 松原 佑介 フロントエンドエンジニア 2018年9⽉BASE⼊社 :
simezi
BASEのプロダクト © - BASE, Inc. ネットショップ作成サービス 「BASE」 ショッピングアプリ 「BASE」 Payment
to the People, Power to the People MISSION
© - BASE, Inc. 2019年10⽉25⽇ マザーズ上場しました
BASEのフロントエンド開発の現状 © - BASE, Inc. サーバーサイド:PHP, Go フロントエンドエンジニア:6名 フロントエンド:Vue.js, TypeScript,
Sketch デザイナー:8名 (2019年10⽉時点)
フロントエンドチームは何をしてきたか © - BASE, Inc. • 管理画⾯刷新プロジェクト開始で jQueryからVue.js+TS化 • SPAではなく、⼤きな機能単位で
MPA(Multi Page Application)化 • 内製のUIコンポーネントライブラリ の作成 ࣍ͷ5Λࢧ͑ΔVue.jsUIίϯϙʔωϯτϥΠϒϥϦΛҭͯΔ
今ではプロジェクト開始から約1年半 © - BASE, Inc. 本⽇はそこで追加で得られた コンポーネントづくりの知⾒ について話します
おしながき © - BASE, Inc. BASEでのコンポーネント設計 Storybookの整備 個別のコンポーネントの実装
© - BASE, Inc. ①BASEでのコンポーネント設計
コンポーネントの種類 © - BASE, Inc. Atomic DesignとContainer Componentの考え⽅を 借りて、役割に応じて⼤きく4つに分類 .
Container Component . Presentational Component . Common Presentational Component . Atom Component ( UIライブラリ )
コンポーネントの種類 © - BASE, Inc. コンポーネントを役割に応じて⼤きく4つに分類 . Container Component .
Presentational Component . Common Presentational Component . Atom Component ( UIライブラリ )
Container Component © - BASE, Inc. • Atomic DesignでいうPageに相当 •
API通信、Storeへのアクセスを⾏うことができる 唯⼀のコンポーネント • 複数のPresentational ComponentやContainer Componentを束ねる役割 • ContainerComponentの中に多少のUIを持つこと は認める
コンポーネントの種類 © - BASE, Inc. コンポーネントを役割に応じて⼤きく4つに分類 . Container Component .
Presentational Component . Common Presentational Component . Atom Component ( UIライブラリ )
Presentational Component © - BASE, Inc. • Template/Organismに相当 • 副作⽤を持たず、与えられたプロパティを表⽰するだ
けのコンポーネント • 具体的なビジネスロジック‧表現に紐づくため再利⽤ 性は考えないコンポーネント • ContainerComponentと PresentationalComponentはディレクトリを分け ず、名前で区別する
コンポーネントの種類 © - BASE, Inc. コンポーネントを役割に応じて⼤きく4つに分類 . Container Component .
Presentational Component . Common Presentational Component . Atom Component ( UIライブラリ )
Common Presentational Component © - BASE, Inc. • Template /
Organism / Moleculeに相当 • Presentational Componentの中でアプリケーション の内部で頻出するデザインのパターンを定義する • 例)全体のヘッダーやページのパンくずとタイトル • 具体的なコンテキストがない抽象的で使い回しができ るコンポーネント群
コンポーネントの種類 © - BASE, Inc. コンポーネントを役割に応じて⼤きく4つに分類 . Container Component .
Presentational Component . Common Presentational Component . Atom Component ( UIライブラリ )
Atom Component © - BASE, Inc. • Atomic DesignでいうMolecule/Atomに相当 •
個別のアプリケーションにとどまらず、サービス全体 で流⽤できるような⼩さいコンポーネント群 • form部品やbuttonなどの利⽤頻度がたかいもの • スタイルの局所的な上書きも許容できるように Scoped CSS / CSS Modulesを使わない • コンポーネント外との関係を決めるスタイルは当てな い 例) margin, float, z-index‧‧‧etc
概念図 © - BASE, Inc.
概念図 © - BASE, Inc. ΠϕϯτͷྲྀΕ
概念図 © - BASE, Inc. ֎෦ͱͷ௨৴ Container͚ͩͰߦ͏
概念図 © - BASE, Inc. Common/Presentational ͲͪΒͰʹͳΕΔ
© - BASE, Inc. ②Storybookの扱い
Storybookに求められる2つの役割 © - BASE, Inc. .サンドボックス 実際のコードに対してどう動くかを試す環境 実装の際のエンジニア向けガイドとしての働き .カタログ 提供されているコンポーネントを網羅的に⾒る
どちらかの要素が⽋けたものが出来上がりがち
サンドボックス性の⾜りないStorybook © - BASE, Inc. 昔ながらのUIカタログの機能しかないケース • やりたいことはわかっても渡すべきprops、 キャッチすべきevent、他コンポーネントと の組み合わせなど、実装に必要な情報が⾜
りない • storybookに置く意味があまりない • 実装を意識しないならsketch上にあるだけ でいい
カタログ性の⾜りないStorybook © - BASE, Inc. 実装者が作るだけ作って満⾜してしまった ケース • コンポーネントが⼀個おいてあるだけ 想定されている使い⽅が伝わらない
• knobsに⼤量のパラメータ パラメータの組み合わせもわからず、作った ⼈にしかわからない。特にデザイナーとはコ ミュニケーションが難しい 協業の場として機能しない
storybookを機能させるために © - BASE, Inc. • Knobsに頼りすぎない • あくまでknobsは補助 •
UIとして利⽤するパターンはなるべく⼀覧できる ように(= カタログ) • 実装に必要な情報はきちんと書く(=サンドボックス) • コンポーネントごとにREADME.mdを⽤意する
コンポーネントごとのREADME.md © - BASE, Inc. @storybook/addon-notesで読み込む 必要な情報 • 簡単なサンプルコード •
動作の仕様 • Propsの値、型、デフォルト値 • Eventの発⽕タイミング、payload • slotの名前 • scoped-slotで渡される値 …etc 将来的には@storybook/addon-docsで markdownを活⽤できるようになるはず (現在はVueのサポートがWIP)
コンポーネントのレイヤ別に必要なこと © - BASE, Inc. ίϯϙʔωϯτͷछྨ Χλϩάੑ αϯυϘοΫεੑ Container Storybook্ʹ
ొ͠ͳ͍ Presentational Common ߴ Atom ߴ ߴ レイヤの低い抽象的なコンポーネントほど説明が必要
© - BASE, Inc. ③個別のコンポーネントの実装
フロントエンドの性質 © - BASE, Inc. • フロントエンドのコードはライフサイクルが短い • 修正=全取替であることが珍しくない •
ドメインロジックに落としづらい細かい分岐の連続 • 例)ある⼀箇所だけ「0円」を「無料」にしたい… • 共通化しても仕様がすぐに変わってしまう
© - BASE, Inc. コンポーネントで作る最⼤の メリットは共通化ではなく 責務の分離
コンポーネントの責務の分離 © - BASE, Inc. • コンポーネントで作ることでスタイル、マークアッ プ、スクリプトを外部に影響しない形でカプセル化 できる •
作る側もとにかく疎結合を優先して、類似コードの 重複を恐れない。 • 本当に必要なパターンと確定したら共通化する • いつでもコードの塊で捨てられる状態をキープする
実装のtips① props © - BASE, Inc. • ObjectやArrayを型に指定するのはなるべく避ける 特にTSを採⽤している場合にはPropTypeを使う props:
{ deliveryInfo: { type : Array as PropType<DeliveryMethod[]> }, payment: { type : String as PropType<Payment>, } },
実装のtips① props © - BASE, Inc. • HTML標準に沿った名前、汎⽤的な名前をつかう ίϯϙʔωϯτར༻ऀ͔ΒΈͨࣗવͳΠϯλʔϑΣΠεΛ৺͕͚Δ name:
'AppInput', props: { id: String, name: String, type: String, value: { default: '', type: [String, Number], }, placeholder: String, }
実装のtips②event © - BASE, Inc. • イベント名にカラフルな語彙を使わない BASEͰ {Πϕϯτͷಈࢺ}:{Πϕϯτͷର} ͱ͍͏ϑΥʔϚοτΛར༻͍ͯ͠Δ
ྫ) update:someValue • XMLͷ໊લۭؒͷϑΥʔϚοτʹ߹Θͤͯಈࢺ+(͋Εతޠ)ͷܗࣜ • ಈࢺͷޠኮΛߜΓγϯϓϧͳ୯ޠΛ͏͜ͱͰݟ௨͕͕͋͠Δ • ಛʹಈࢺίϯϙʔωϯτʹ ͨ͠Πϕϯτ໊Λ͚ͭͳ͍ <app-controller @click:search="openSearchBox" @change:all="checkAll" @change:sortOrder="onChangeSortOrder" @change:editMode="onChangeEditMode" @change:keyword="onChangeKeyword" @search="onSearch"> </app-controller>
実装の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) }
実装のtips③style © - BASE, Inc. • classを条件分岐や処理で渋滞させない • すべてclassで表現するとパターンが増えたときに 爆発しがち
// Մಡੑͷ͍ίʔυ <span :class="[type ? 'c-'+ type' : '', hasError ? ‘error’ : ‘’]”></span>
実装のtips③style © - BASE, Inc. • ⼀時的な状態に依存するスタイルはdata-*やaria-* と属性セレクタの組み合わせで当てる • 例)
ローディング中、選択中か、など <app-component class=“foo” :aria-selected=“''+isHoge"> .foo { &[aria-selected="true"] { color: $green; } &[aria-selected="false"] { color: $gray; } }
実装のtips④scoped-slot © - BASE, Inc. コンポーネントの内部状態を⼀元管理するコンポー ネントが欲しくなる場合にはscoped-slotを利⽤す る 例) •
テーブルのヘッダとリストの結びつき管理 • モーダルのトリガとなるコンポーネントとモー ダルのコンテンツ
実装のtips④scoped-slot © - BASE, Inc. モーダルのサンプル <app-modal> <!-- Ϟʔμϧͷදࣔঢ়ଶ͜ͷίϯϙʔωϯτͷ෦ʹӅṭ͢Δ -->
<template #activator="{activate}"> <!-- ϞʔμϧදࣔͷτϦΨͱͳΔؔΛscoped-slotͰఏڙ --> <app-button @click=activate>දࣔ͢Δ</app-button> </template> <template #body="{deactivate}"> <!-- ϞʔμϧඇදࣔͷτϦΨͱͳΔؔΛఏڙ --> <div>ίϯςϯπ</div> </template> </app-modal>
まとめ © - BASE, Inc. • コンポーネントでいちばん⼤事なのは責務の分離 • 特にContainerとPresentationalなコンポーネン トの役割わけをきっちり守るのは重要
• いつでもコード(特にUI側)を捨てられるように。 • Storybookには広い利⽤者に向けたおもてなしの⼼ が必要 • ちょっとした⾶び道具的な修正でコンポーネントの前提が壊れても泣かない
© - BASE, Inc. ありがとうございました