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
simezi9
October 30, 2019
Programming
13
49k
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.1k
VBScript meets Vue.js 〜20年越しの出会い〜
simezi9
9
1.7k
Other Decks in Programming
See All in Programming
わたしの星のままで一番星になる ~ 出産を機にSIerからEC事業会社に転職した話 ~
kimura_m_29
0
180
Mermaid x AST x 生成AI = コードとドキュメントの完全同期への道
shibuyamizuho
0
160
バグを見つけた?それAppleに直してもらおう!
uetyo
0
180
今年のアップデートで振り返るCDKセキュリティのシフトレフト/2024-cdk-security-shift-left
tomoki10
0
200
20年もののレガシープロダクトに 0からPHPStanを入れるまで / phpcon2024
hirobe1999
0
430
PHPで作るWebSocketサーバー ~リアクティブなアプリケーションを知るために~ / WebSocket Server in PHP - To know reactive applications
seike460
PRO
2
110
StarlingMonkeyを触ってみた話 - 2024冬
syumai
3
270
range over funcの使い道と非同期N+1リゾルバーの夢 / about a range over func
mackee
0
110
Zoneless Testing
rainerhahnekamp
0
120
今からはじめるAndroidアプリ開発 2024 / DevFest 2024
star_zero
0
1k
Cloudflare MCP ServerでClaude Desktop からWeb APIを構築
kutakutat
1
540
「Chatwork」Android版アプリを 支える単体テストの現在
okuzawats
0
180
Featured
See All Featured
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
159
15k
Automating Front-end Workflow
addyosmani
1366
200k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
For a Future-Friendly Web
brad_frost
175
9.4k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
111
49k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
45
2.2k
Optimizing for Happiness
mojombo
376
70k
Building an army of robots
kneath
302
44k
Bash Introduction
62gerente
608
210k
Side Projects
sachag
452
42k
Agile that works and the tools we love
rasmusluckow
328
21k
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. ありがとうございました