Upgrade to Pro — share decks privately, control downloads, hide ads and more …

スタディストのVue

mtakeda
November 19, 2023

 スタディストのVue

React vs Vue.js討論会〜好きで語る技術の話〜
https://timeedev.connpass.com/event/300375/

Youtube:
https://www.youtube.com/watch?v=j6cKBC3Gwe4

mtakeda

November 19, 2023
Tweet

Other Decks in Programming

Transcript

  1. Copyright © 2023 Studist Corporation. all rights reserved. 自己紹介 3

    竹田 求志です • 基本機能強化チームのリーダー • β版開発 → 価値検証 → 正式版開発の 動きを続けている • 趣味:音楽、犬、ゲーム ◦ AC6を出してくれて嬉しい
  2. Copyright © 2023 Studist Corporation. all rights reserved. 導入の経緯 6

    • 2018年秋、UIリニューアルを行うに当たってフレームワークを検討 • Angular、React、Vue.js を比較検討した • Vue.js は習熟が比較的容易と判断された ◦ → Vue.js を採用
  3. Copyright © 2023 Studist Corporation. all rights reserved. 歴史 7

    • 2018年 ◦ Vue.js 導入 ◦ Storybook 導入 ◦ ドメイン駆動Vuexで複雑さに立ち向かう • 2019年 ◦ Storybook による Visual Regression Test を導入 • 2020年 ◦ E2E導入 • 2021年 ◦ 機能開発を止めずに、6万行の TypeScript 移行を完了 ◦ Composition API導入開始 • 2022年 ◦ IE のサポートを終了せずに IE のサポートを終了 ◦ 機能開発を止めずに、500コンポーネント規模のVue 3 移行を完了 • 現在 ◦ Vuex → Pinia 移行を進めている
  4. Copyright © 2023 Studist Corporation. all rights reserved. SFC 10

    <template> COUNT: {{ count }} <button @click="increment">increment</button> <button @click="decrement">decrement</button> </template> <script lang="ts"> import { defineComponent } from 'vue' export default defineComponent({ data() { return { count: 0 } }, methods: { increment() { this.count++ }, decrement() { this.count-- } } }) </script> <style scoped> button { font-weight: bold; } </style>
  5. Copyright © 2023 Studist Corporation. all rights reserved. SFC 11

    <template> COUNT: {{ count }} <button @click="increment">increment</button> <button @click="decrement">decrement</button> </template> <script lang="ts"> import { defineComponent } from 'vue' export default defineComponent({ data() { return { count: 0 } }, methods: { increment() { this.count++ }, decrement() { this.count-- } } }) </script> <style scoped> button { font-weight: bold; } </style> ロジック(JavaScript or TypeScript) テンプレート(HTML) スタイル (CSS)
  6. Copyright © 2023 Studist Corporation. all rights reserved. HTML感覚で書ける分岐とリストレンダリング 12

    <template> COUNT: {{ count }} <button @click="increment">increment</button> <p v-if="errorMessage" v-text="errorMessage" /> </template> <script lang="ts"> import { defineComponent } from 'vue' export default defineComponent({ data() { return { count: 0 } }, computed: { errorMessage() { if (this.count > 10) { return '10を超えちゃだめです' } return '' } }, methods: { increment() { this.count++ } } }) </script> 条件を満たした時だけ描画するv-if
  7. Copyright © 2023 Studist Corporation. all rights reserved. HTML感覚で書ける分岐とリストレンダリング 13

    <template> <div v-for="(message, i) in messages" :key="i"> {{ message }} </div> </template> <script lang="ts"> import { defineComponent } from 'vue' export default defineComponent({ data() { return { messages: ['hoge', 'fuga', 'piyo'] } } }) </script> 配列の中身で繰り返し表示が出来る v-for SFC, v-if, v-for などにより完成形がイメージしやすい(直感的な宣言的UI)
  8. Copyright © 2023 Studist Corporation. all rights reserved. HTML/CSSに馴染みがあって理解しやすかった 14

    HTML/CSSの経験に寄った開発者達 ・フロントエンド専門がいない ・リニューアル前はRailsのerb(≒html/css) HTML/CSS 経験を活かした開発が出来るVue ・template, script, styleをまとめて書ける SFC ・直感的な宣言的UI Vue.js という選択は当時の状況にマッチしていた
  9. Copyright © 2023 Studist Corporation. all rights reserved. パフォーマンスの劣化を意識せずに開発出来た 16

    • Vue.js は影響のある箇所だけが再レンダリングの対象となる (fine-grained Reactivity) • 親コンポーネントに変更があっても子コンポーネントは再レンダリングされない • 仮想DOMなどの知識を持たずに機能開発に集中しても、パフォーマンスが劣化しづらい
  10. Copyright © 2023 Studist Corporation. all rights reserved. パフォーマンスの劣化を意識せずに開発出来た 17

    • Vue.js は影響のある箇所だけが再レンダリングの対象となる (fine-grained Reactivity) • 親コンポーネントに変更があっても子コンポーネントは再レンダリングされない • 仮想DOMなどの知識を持たずに機能開発に集中しても、パフォーマンスが劣化しづらい 仮想DOMとか詳しくないけど、 そこは Vue に任せて機能開発に集中だ!
  11. Copyright © 2023 Studist Corporation. all rights reserved. エコシステムに悩まずに進められた 19

    • Vueで使うエコシステムは基本公式一択 • スタディストでは以下を利用 ◦ Vuex (現在は piniaに移行中) ◦ Vue Router ◦ VueI18n ◦ Vue Loader ◦ Vue Test Utils ◦ eslint-plugin-vue • エコシステムを迷わずに決めて、進めることが出来る 公式 こっちでいいのね
  12. Copyright © 2023 Studist Corporation. all rights reserved. 日本語ドキュメントを読みながら開発出来た 21

    • 当時Vue.jsの日本語ドキュメントが他に比べて充実していた • 学習を進めるためにネットの海をあちらこちらに行く必要がなく、効率的に学ぶことが出来た
  13. Copyright © 2023 Studist Corporation. all rights reserved. 習熟が容易だった理由まとめ 23

    • HTML/CSSに馴染みのあるメンバーx HTML/CSSを経験を活かせるフレームワーク • 機能開発に集中しても劣化しづらいパフォーマンス • エコシステムが決まっている • 日本語ドキュメントが豊富
  14. Copyright © 2023 Studist Corporation. all rights reserved. Vue3.x になった今どうか

    24 • HTML/CSSに馴染みのあるメンバーx HTML/CSSを経験を活かせるフレームワーク ◦ このケースで素早く開発が始められるのは変わらない • 機能開発に集中しても劣化しづらいパフォーマンス ◦ 改善が続けられている • エコシステムが決まっている ◦ 実質1択状態なのは変わらず ▪ 「Vue経験あり」の人はまず同じエコシステムの経験を積んでいる • 日本語ドキュメントが豊富 ◦ 今もドキュメントしっかりしている ◦ 他との差はあまり無い
  15. Copyright © 2023 Studist Corporation. all rights reserved. Composition APIの活用

    27 • 従来のOptions APIに加えてComposition APIが登場 ※ React Hooks の Vue 版 • コンポーザブル関数として状態を持つロジックをコンポーネントから分離することで、コン ポーネント間での共通化や、ロジックのテストが行いやすくなった
  16. Copyright © 2023 Studist Corporation. all rights reserved. Composition APIの活用

    28 <script setup lang="ts"> import { useCounter } from '@/compositions/useCounter' const { count, increment, decrement } = useCounter(0) </script> <template> カウント: {{ count }} <button @click="increment">increment</button> <button @click="decrement">decrement</button> </template> Sample.vue import { ref } from 'vue' export function useCounter(initialValue = 0) { const count = ref(initialValue) const increment = () => count.value++ const decrement = () => count.value-- return { count, increment, decrement } } useCounter.ts <script setup lang="ts"> import { ref } from 'vue' const count = ref(0) const increment = () => count.value++ const decrement = () => count.value-- </script> <template> COUNT: {{ count }} <button @click="increment">increment</button> <button @click="decrement">decrement</button> </template> Sample.vue コンポーザブル関数として切り出し Before After 状態とロジックを使える
  17. Copyright © 2023 Studist Corporation. all rights reserved. コンポーザブル関数の嬉しいこと 29

    • 共通化が出来る • テストが出来る! • コードも読みやすくなる! import { useCounter } from '@/compositions/useCounter' describe('useCounter', () => { it('テスト!', () => { const { count, increment, decrement } = useCounter(2023) expect(count.value).toBe(2023) increment() expect(count.value).toBe(2024) decrement() expect(count.value).toBe(2023) }) }) useCounter.spec.ts 状態とロジックが意図通りに動 いていることをテストしやすい
  18. Copyright © 2023 Studist Corporation. all rights reserved. 共通化の予定が無くても切り出す 30

    <script setup> </script> <template> … </template> 共通化の予定は無いが、少々複雑なロジック 他のコンポーネントでは使わないかもだけど、 テスト/可読性のためにも切り出そうぜ!!
  19. 37 <script> <script> + setup() <script setup> Options API Options

    API & Composition API Composition API • 昔からあるコンポーネントにコンポーザブル関数を 組み込んだもの • そこまで複雑でないコンポーネント
  20. 38 <script> <script> + setup() <script setup> Options API Options

    API & Composition API Composition API • 複雑性の高いコンポーネント • <script setup> を試すために書かれたコンポーネントも 少々存在する
  21. Copyright © 2023 Studist Corporation. all rights reserved. Options APIを使い続ける理由

    39 • すでに多くのOptions APIで書かれたコンポーネントが存在し、それをComposition APIに統一す るのはコストが高い ◦ そもそも、複雑度か高くないコンポーネントを頑張ってComposition APIに移行するメリッ トは無い • Options APIの方が書き慣れているエンジニアが多い • Options APIが非推奨になる予定は無いと公式に記載されている → Options API, Composition APIどちらも利用可としている (とはいえ今後Composition APIでしか出来ないことが増える可能性もあり、様子見の段階)
  22. Copyright © 2023 Studist Corporation. all rights reserved. Options APIは公式にも価値を認められている

    40 > Options API は、コンポーネントコードを書くときに「考えることを減らす」ことを可能にし、 > それが多くのユーザーに支持されている理由です。 > Options API は Vue の不可欠な要素であり、多くの開発者がVue を愛する理由にもなっています。 > Composition API の利点の多くは大規模プロジェクトでこそ現れるものであり、多くの低~中程度の > 複雑性のシナリオにおいては Options API が堅実な選択肢であり続けることも理解しています。 Vue公式ドキュメントより
  23. Copyright © 2023 Studist Corporation. all rights reserved. Vuexの使い方 42

    • Vuexをドメインの処理に集中させる ◦ ドメインの複雑さはVuexに閉じ込める • コンポーネントは理想的なモデルをVuexから受け取り、UI表現に集中する • APIからドメインデータを取得する時以外は使わない
  24. Copyright © 2023 Studist Corporation. all rights reserved. Vuex 43

    UI API store action getter mutation state API データ モデル
  25. Copyright © 2023 Studist Corporation. all rights reserved. Pinia 44

    UI API store action state API データ モデル
  26. Copyright © 2023 Studist Corporation. all rights reserved. Vuex →

    Pinia 45 • ドメインの複雑さを隠蔽するために利用する方針はそのままに、Piniaに移行中 ◦ コンポーネントがUIの表現に集中出来る ▪ APIに変更があってもstore側で吸収出来る ◦ 開発者としても利用用途が明確で使いやすい • Vuexでボイラープレート的に記載していた色々が無くなって嬉しい
  27. Copyright © 2023 Studist Corporation. all rights reserved. UIリニューアルの時点でアトミックデザインを採用 47

    • UIリニューアルプロジェクトの中で、コンポーネント分割の考え方を模索する中で導入 • 5つの要素に分解して考える ◦ Pages (画面) ◦ Templates (ページテンプレート) ◦ Organisms (有機体) ◦ molecules (分子) ◦ Atoms (原子)
  28. Copyright © 2023 Studist Corporation. all rights reserved. UIリニューアルの時点でアトミックデザインを採用 48

    • スタディストではTemplateを使わない形で採用してます ◦ Pages ◦ Organisms ◦ Molecules ◦ Atoms • 共通のレイアウトコンポーネントは別途使うこともある
  29. Copyright © 2023 Studist Corporation. all rights reserved. コンポーネントの境界を迷わないように 53

    分類 用途 storeへのアクセス Pages ルート(URL)に対応したページ 可 Organisms Moleculesを組み合わせて一連の機能を提供 可 Molecules Atomsを組み合わせて単一の機能を提供 不可 Atoms それ以上分割できないUIの最小単位 不可
  30. Copyright © 2023 Studist Corporation. all rights reserved. コンポーネント分割はアトミックデザイン 54

    • アトミックデザインを導入することで分割の基準を明確にしている ◦ 作りやすい、探しやすい、管理しやすい • 下位コンポーネントが上位コンポーネントを知る必要が無いので再利用しやすい • storeにアクセス出来る層を限定することで、下位コンポーネントのテスタビリティが高い