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
vueで中規模以上のフロントエンドを組んでいて 役に立ったtips
Search
Nkowne63
January 28, 2020
Technology
5
3.1k
vueで中規模以上のフロントエンドを組んでいて 役に立ったtips
自社サービスを構築する際に実施した施策の簡単な解説です
Nkowne63
January 28, 2020
Tweet
Share
More Decks by Nkowne63
See All by Nkowne63
TypeScriptのコード生成をつらくしないために
neutron63zf
1
680
2020-11-05-side-effects-composition__1_.pdf
neutron63zf
1
420
20200128_nkowne63
neutron63zf
0
35
Vueで「見た目」「振る舞い」を分離してみよう
neutron63zf
0
580
20190523_nkowne63zf_1.pdf
neutron63zf
0
400
「つなぎこみ」を自動化する
neutron63zf
0
470
for文禁止縛り in JS
neutron63zf
0
700
Other Decks in Technology
See All in Technology
LINEギフトのLINEミニアプリアクセシビリティ改善事例
lycorptech_jp
PRO
0
240
ペアプログラミングにQAが加わった!職能を超えたモブプログラミングの事例と学び
tonionagauzzi
1
140
[CATS]Amazon Bedrock GenUハンズオン座学資料 #2 GenU環境でRAGを体験してみよう
tsukuboshi
0
140
職種に名前が付く、ということ/The fact that a job title has a name
bitkey
1
240
AIエージェント完全に理解した
segavvy
4
260
LINE API Deep Dive Q1 2025: Unlocking New Possibilities
linedevth
1
160
モノリスの認知負荷に立ち向かう、コードの所有者という思想と現実
kzkmaeda
0
110
AWS のポリシー言語 Cedar を活用した高速かつスケーラブルな認可技術の探求 #phperkaigi / PHPerKaigi 2025
ytaka23
7
1.5k
AIエージェントキャッチアップと論文リサーチ
os1ma
6
1.2k
どっちの API SHOW?SharePoint 開発における SharePoint REST API Microsoft Graph API の違い / Which API show? Differences between Microsoft Graph API and SharePoint REST API
karamem0
0
100
Dapr For Java Developers SouJava 25
salaboy
1
130
Keynote - KCD Brazil - Platform Engineering on K8s (portuguese)
salaboy
0
120
Featured
See All Featured
KATA
mclloyd
29
14k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
25k
Documentation Writing (for coders)
carmenintech
69
4.7k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
How STYLIGHT went responsive
nonsquared
99
5.4k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
How to Ace a Technical Interview
jacobian
276
23k
Making Projects Easy
brettharned
116
6.1k
Art, The Web, and Tiny UX
lynnandtonic
298
20k
Optimising Largest Contentful Paint
csswizardry
35
3.2k
Building Adaptive Systems
keathley
41
2.5k
Transcript
vueで中規模以上のフロン トエンドを組んでいて 役に立ったtips
自己紹介 張 たいよ (GitHub: @neutron63zf) 東京大学理学部物理学科 4年 • ventus-inc ◦
JavaScript ( Vue.js / Nuxt.js ) ◦ Golang / Firebase • (元)東京大学五月祭常任委員会 ◦ AWS / Nginx / Docker ◦ Node.js ( Express )
作っているサービス(whooop!) • スポーツチームの発行したカード を買うことで応援できる • カードを買うことでイベントなどの さまざまな特典が得られる • オークションなどで、ユーザー間 でデータをやりとりできる
構成 • 動機 • 通信の一本化 • vuexの構成 • 各コンポーネントとデータフロー •
実際にやってみて・まとめ
前提知識 • Vue ◦ 表示をコンポーネントという単位に分割して書くことができる • Vuex ◦ (すごくざっくり言うと) Storeというものに状態をまとめ、それに対して操作をする。
◦ 「一方向のデータフロー」を課すことで、挙動を予測しやすくする。 • Nuxt ◦ Vueでサーバーサイド・レンダリング( SSR)をするときに便利なフレームワーク ◦ ほとんど普通の Vueを書く感覚でSSRができる反面、制約がきついところも
動機:「いつの間にかアプリケーションが大きく...」 • whooopは当初、ページは20ほど、エンドポイントは40ほどのサービスだった。 • しかし、いつの間にか機能の増加とともに、ページ数もエンドポイントも倍以上に! ◦ 現在はエンドポイント 100近く(統合中...)、ページ数50ページ程度 • 当初のコードではだんだん改良、機能追加が厳しくなっていった
アプリケーションが想定を超えて大きくなり、当初の書き方だと通用しなくなった
例(1): リクエスト処理が不明確 • APIで通信する際、上はuserIdを与えればいいということ がわかるが、下はAPI ドキュメントを読まないと、何を与え るべきか不明 • 生でHTTP Methodやurl、パラメーターを書いていて、そ
れが至るところにあるので、変更が大変
例(2): データ変換・保持がまちまち • teamsとteamlistみたいに、名前がかぶっていたり、通信 後にキャメルケースに変換しているか否かがまちまち • どのようなデータ構造でストアに保管されているかはスト アごとに異なり、新しく追加されるものについても、「今ま でのステートに統合される」のか「今までのステートを上 書きする」のかが異なる
結論:しんどい • ストアが使いづらいことこの上ないので、ストアのステートからではなく、毎回ストアのアクションの返り値を 直接コンポーネントにセットするコードが多発 ◦ ストアを使う意味 ... • 上と並行して、ストアにデータを記録することなくレスポンスをパースするだけのコードも多発 •
たまに変なデータ変換をかけている部分は逆変換をかけないと使えないことも →デザインのリニューアルついでに大幅にリファクタリングするぞ! (このスライドはその時にいろいろ試した施策をいくつか抜粋して紹介している)
通信の一本化
△通信したい ◦通信して〇〇したい そもそもフロントから通信をするときに、いちいち postかgetかput か。urlはどこか、どこのパラメーターにどのデータをどんな形式で 入れるかは気にしたくない。 そういうのはいちいち意識せずに済むように、 関数でリクエスト形 式等の内部構造はある程度ラップする。 ラップした関数は集めておいて、そこからだけ使うようにする。
呆れるほど単純だが、これを徹底するだけで、そうでない場合に 比べてかなり見通しはよくなる。
APIドキュメントから自動生成 APIの数が増えてくると、単純に先程のようなコードを錬成するの がめんどくさくなってくるので、 Open APIや、API Blueprintといっ た、ある程度まとまったAPIドキュメントがある場合は、そちらから APIクライアントを自動で作ると楽。 例えば、Swaggerの場合はSwagger-Clientから、自動でSwagger ドキュメントを読み込み、APIクライアントを動的に作れる。
(一瞬でつなぎ込みが終わりちょっとした全能感に浸れる)
Vuexの構成
APIデータ保持ストアの分離 • propsのバケツリレーの緩和 • ページをまたいだ状態の保持 • APIから取得したデータの保持 最初の2つは、ユースケースごとにモジュールを作ってもそんなに荒れな い。 しかし、通信(つまり3つ目)は統一されていたほうがアプリケーションが作
りやすいのでちゃんと考える。
ネストされたデータの展開(1) APIリクエストを扱っていると、あるオブジェクトのプロパティーに関連 するオブジェクトが入っていることがよくある。(例: articleのcomments プロパティーに、commentというオブジェクトが配列で入っている) だが、normalizrというライブラリを使うと右のように、オブジェクトの種 類ごとに展開でき、「key-value」ごとにアクセスできる形式に変換でき る。
ネストされたデータの展開(2) これにより、オブジェクトの種類ごとにストアを作成し、 normalizrに より分解されたデータを入れることにより、ストアの中のデータの入 り方を統一することができるようになる。 なお、normalizrでは、何も指定しないとidでしかアクセスできるよう にならないが、他のキーでもアクセスしたい場合は、そのキーと idの 対応表を作成しておくとよい。
APIストアでやること 以上のことをまとめると、APIストアでやることは以下の通り。 • (初期化時)オブジェクトの種類だけ配下のモジュールを動的に登録する。 • リクエストのアクションがdispatchされたら、通信を実行 • レスポンスをnormalizrにかけて、各モジュールに分配
APIストアでやること(実際のコード例) 2行目でリクエストを実行し、 3行目でnormalizrにかけて、 5行目でストアに保存
(余談)リクエストを送るメソッドの追加 whooopでは、リクエストを送る際はストアのリクエストアク ションをディスパッチすればいいようにしてあるが、毎回 「this.$store.dispatch」、なんて書いているのは正直めんど くさい。 なので、vueのインスタンスに「$apiRequest」を、nuxtのコ ンテキストに「apiRequest」をプラグインし、それでリクエスト が送れるようにしてある。
viewに依存するストアの部分 基本的に注意すべき部分はあまりないが、以下の 2ルールだけ課した。 • ステートは最低限必要なものにすること(何でもかんでもつめこまない) ◦ ページをまたがって引き継ぐ必要のあるデータ。そして、 props渡しだと不可能なデータの運搬(モーダルなど) ◦ そうで無いデータはコンポーネントのステートとして処理できるので、あまりストアの旨味がない
• アクション・ミューテーションも最低限必要なものにすること ◦ つまり、複数のアクションのうち共通する処理であっても、ストアの内部でしか使われないのならば、「アクショ ン」や「ミューテーション」ではなく、関数として切り出す 特に2つ目のルールは、ストアが大きくなったときにスパゲッティーコード化することを多少は緩和してくれる。
各コンポーネントと データフロー
Atomic Designを導入する(1) デザインをリニューアルする際に、「 Atomic Design」 を導入し、コンポーネントの再利用性を高めることにし た。 だが、右の図にあるような「よくネットである Atomic Design」の他にも、会社ごとにたくさんの「オレオレ
Atomic Design」なるものがあり、どれもよさげで迷っ た。 結局、厳密でなくても、「階層的にコンポーネントを構 築していく」というコンセプトの元で自分たちなりにルー ルを決めることにした。
Atomic Designを導入する(2) 悩んだ末、「Templates」の代わりに、「Layouts」という 層を「Organisms」と「Pages」の間に置くことにした。 そして、以下のルールを課した。 • それぞれの層のコンポーネントは、それよりも 下層のコンポーネントだけから作られること。 • Organisms以上の層では、CSSを基本的には
書かず、クラスをつけるなどで対処する。 代わりに 「Layouts」 を入れる
CSSとAtomic Design Vueでは単一ファイルコンポーネント内で CSSを書くこと ができる。 だが、Organism層以上では基本的にはそれを使用せ ずに、位置の微調整などはクラスをつけることで行っ た。(例:flexボックスにしたい場合はflexクラスをつけ る) これにより、CSSの重複などを防ぐことができるほか、
コーディングの指針が明確になる 。(CSSがどうしても欲 しいなら下の層にうつすか、新たにクラスを生やす。)
どの層かの判断基準 Atomic Designでおそらくいちばん困るのが 「このコンポーネントはどの層に属するのか」という判断 で、実際 に運用をしたい場合はここを ある程度スムーズに判断できるような基準を設けておく とかなりやりやすい。 whooopでは現在以下のように区分けしている。 •
Atoms … これ以上分解すると機能として成り立たない単位(チェックボックス等) • Molecules … 特定のオブジェクトに依存しないが、 Atomsを複数組み合わせて実現できる単位(カ ルーセルや、検索窓等) • Organisms … 特定の種類の、単一のオブジェクトを表示する単位(ユーザーの持つカード等) • Layouts … 複数種類や、複数個のオブジェクトを表示する単位(ユーザーの持つカードの一覧)
OrganismsとLayoutsの例 右の画像は「チームの中で、どれくらいカードを集めている かのランキング」という「Layouts」 その中の1行1行が「ユーザーが何位で、何枚カードを持っ ているか」を表示する「Organisms」
コンポーネントによるリクエストの構築 vueのコンポーネントがbuildRequestというオプションを持 てるようにして、リクエストを各コンポーネントで構築できるよ うにした。 これにより、「使っているコンポーネントにそぐわないリクエス トを送ってしまう」という事態をかなり減らせる。 なお、そのまま送らないのは、 nuxtのSSR時は、基本 pagesからしかリクエストを送れないため
コンポーネントによるリクエストの構築(2) VueのScoped Slotsという機能を用いてリクエストを送っ て、子のコンポーネントに送るだけのコンポーネントを作る と いう手法もかなり有効。 これにより、getリクエストに関しては宣言的に書くことができ るだけでなく、loadingやerror時の分岐など、状態に由来す る処理を共通化することができる。 「ダミーデータで表示している部分で実際に
api由来のデー タを使うようにする」という書き換えが一瞬で終わる。
ストアのデータの取得(1) サーバーから取得したデータはストアに入っているわけだ が、そのままでは取得するのが少し面倒。 そこで、オブジェクトの種類ごとに 「idや、idの配列から簡単 にストアをクエリできる関数」 を作っておくとストアから取得す る部分が随分すっきりする。 whooopでは、(normalizrのために定義した)オブジェクトの 一覧から、ストアだけでなく、こうしたヘルパー関数も自動で
作っている。
ストアのデータの取得(2) また、normalizrを通すとネストされたデータは idに変換され てしまうので、ヘルパー関数でそれらを再構築できるように するオプションも実装した。(右の画像では、ストアからオー クションの配列を取得し、ordersというキーについて、またス トアから注文の配列を取得し、付加している。) とはいえ、これを使わずに実装できるケースがほとんど。
実際にやってみて ・まとめ
実際にやってみて(1) 快適!! フロントエンドで面倒になりがちな • CSS • つなぎ込み の2つの負担をかなり減らせる。そして機能に集中してコードを書くことができるようになる。 それなりに準備は大変だったがおすすめできる。
実際にやってみて(2) 一方で、Atomic Designはともかく、リクエストを送る部分はかなり「オレオレフレームワーク」になってしまった 感が否めない。(通常のvue, vuexの上に積み上げたものが大きい) そのため、はじめて入ったメンバーに対しては、説明をした上で、比較的小さな、しかしこれらを一通り経験で きるようなタスクを振ることで慣れさせる期間を設けている。
まとめ • APIリクエストは、http methodなどをラップして一箇所にまとめておく • APIデータをストアに出し入れする方法は用意しておくと楽 • 表示などで使うストアは、ステートもアクションもミューテーションも最低限に抑える • Atomic
Designをやるなら階層を分ける基準は明確にしておいた方がいい • コンポーネントがリクエストを構築できるようにしておくとよい