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
660
2020-11-05-side-effects-composition__1_.pdf
neutron63zf
1
420
20200128_nkowne63
neutron63zf
0
33
Vueで「見た目」「振る舞い」を分離してみよう
neutron63zf
0
570
20190523_nkowne63zf_1.pdf
neutron63zf
0
390
「つなぎこみ」を自動化する
neutron63zf
0
470
for文禁止縛り in JS
neutron63zf
0
700
Other Decks in Technology
See All in Technology
Developers Summit 2025 浅野卓也(13-B-7 LegalOn Technologies)
legalontechnologies
PRO
1
740
利用終了したドメイン名の最強終活〜観測環境を育てて、分析・供養している件〜 / The Ultimate End-of-Life Preparation for Discontinued Domain Names
nttcom
2
200
生成 AI プロダクトを育てる技術 〜データ品質向上による継続的な価値創出の実践〜
icoxfog417
PRO
2
160
関東Kaggler会LT: 人狼コンペとLLM量子化について
nejumi
3
600
自動テストの世界に、この5年間で起きたこと
autifyhq
10
8.6k
エンジニアのためのドキュメント力基礎講座〜構造化思考から始めよう〜(2025/02/15jbug広島#15発表資料)
yasuoyasuo
18
6.9k
Developer Summit 2025 [14-D-1] Yuki Hattori
yuhattor
19
6.3k
2025-02-21 ゆるSRE勉強会 Enhancing SRE Using AI
yoshiiryo1
1
380
2024.02.19 W&B AIエージェントLT会 / AIエージェントが業務を代行するための計画と実行 / Algomatic 宮脇
smiyawaki0820
14
3.6k
リーダブルテストコード 〜メンテナンスしやすい テストコードを作成する方法を考える〜 #DevSumi #DevSumiB / Readable test code
nihonbuson
11
7.3k
白金鉱業Meetup Vol.17_あるデータサイエンティストのデータマネジメントとの向き合い方
brainpadpr
6
770
Culture Deck
optfit
0
430
Featured
See All Featured
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
The Invisible Side of Design
smashingmag
299
50k
How GitHub (no longer) Works
holman
314
140k
Agile that works and the tools we love
rasmusluckow
328
21k
Fontdeck: Realign not Redesign
paulrobertlloyd
83
5.4k
Fashionably flexible responsive web design (full day workshop)
malarkey
406
66k
Scaling GitHub
holman
459
140k
The Art of Programming - Codeland 2020
erikaheidi
53
13k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
100
18k
Making Projects Easy
brettharned
116
6k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
29
1k
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をやるなら階層を分ける基準は明確にしておいた方がいい • コンポーネントがリクエストを構築できるようにしておくとよい