Slide 1

Slide 1 text

Copyright © LIXIL Corporation. All rights reserved. サービス開発における Vue3とTypeScriptの親和性について からころ(@karan_corons) / Tsukuha Kawakami TSKaigi 2024 株式会社LIXIL Marketing Dev Ops. System Dev. & Ope. Digital E-Application Exp

Slide 2

Slide 2 text

2
 自己紹介 - HN / Name - からころ(@karan_corons)/ Tsukuha Kawakami - 所属 - 株式会社LIXIL - やっていること - MyLIXILという共通認証基盤の開発・運用 .etc - フロントエンドを基軸にバックエンドからクラウド, CI/CDまで - Zennでの技術記事の執筆など - よく使う技術 - TypeScript, JavaScript, Node.js, Vue.js .etc

Slide 3

Slide 3 text

3
 アジェンダ 1. はじめに 2. Vue.jsの概要 3. Vue.jsコミュニティ発のツールチェインについて 4. Vue.jsのTypeScript対応の経緯について 5. 状態管理と型 6. 型を利用してデータフローを可視化しよう 7. おわりに

Slide 4

Slide 4 text

4
 聞いてほしい方・話さないこと 聞いてほしい方 - Vue2からVue3への移行で悩んだことのある方 - Vue2の経験はあるけど、Vue3はあまり触っていない方 - その他、フロントエンドTypeScriptに興味がある方 .etc 話さないこと - Vueやその他ツールチェインの環境構築について - モダンフロントエンドフレームワークの基礎的内容 - Vue.jsの細かい仕様やTypeScriptに関係しないこと

Slide 5

Slide 5 text

5
 Vue.jsを使ったことがある人 どのくらいいますか?󰢨

Slide 6

Slide 6 text

6
 はじめに 話したいこと - Vue2も昨年末でEOLを迎えましたが、Vue2からVue3にかけて TypeScript対応はどういう経緯を辿ったか - Vue3が正式リリースされてすでに4年弱経っている現在 Vue3とTypeScriptの親和性は具体的にどうなっているか 今日持ち帰って欲しいこと - Vue3とTypeScriptの親和性への理解 - 実際に用意しているテストリポジトリで実感

Slide 7

Slide 7 text

7
 親和性とは?

Slide 8

Slide 8 text

8
 親和性とは? Logic Compositon(論理構成) Type Inference(型付け) × ref: vuejs/rfcs: https://github.com/vuejs/rfcs/pull/42/files#diff-d721e848484a3365870d3616ba5a6454a440bb4bc9b4f31ca02f1071edeb434eR89-R156

Slide 9

Slide 9 text

9
 Vue.jsの概要 1 Web ユーザーインタフェース 構築のための、親しみやすく、 パフォーマンスと汎用性の高い フレームワークです。 pages/index.vue Child1.vue index.vue 右図のようにVue SFCを作成 できます。

Slide 10

Slide 10 text

10
 Vue.jsの概要 2 親コンポーネントから 子コンポーネントへのデータの 受け渡しはこのように書け ます。 components/Child1.vue

Slide 11

Slide 11 text

11
 Vue.jsの概要 2 親コンポーネントから 子コンポーネントへのデータの 受け渡しはこのように書け ます。 components/Child1.vue pages/index.vue

Slide 12

Slide 12 text

12
 Vue.jsの概要 3 propsのバケツリレー(Props Drilling) ref: https://ja.vuejs.org/assets/prop-drilling.XJXa8UE-.png

Slide 13

Slide 13 text

13
 Vue.jsの概要 4 逆に子コンポーネントから、 親コンポーネントへのデータ の受け渡しは、 Event Emitting を利用し、 このように書けます。 components/Child.vue

Slide 14

Slide 14 text

14
 Vue.jsの概要 4 逆に子コンポーネントから、 親コンポーネントへのデータ の受け渡しは、 Event Emitting を利用し、 このように書けます。 components/Child.vue

Slide 15

Slide 15 text

15
 Vue.jsの概要 4 Emitされたイベントは、 親コンポーネント側で、 ハンドルすることが可能で、 イベントハンドラの引数から データを受け取って処理を することができます。 pages/index.vue

Slide 16

Slide 16 text

16
 Vue.jsの概要 4 Emitされたイベントは、 親コンポーネント側で、 ハンドルすることが可能で、 イベントハンドラの引数から データを受け取って処理を することができます。 pages/index.vue

Slide 17

Slide 17 text

17
 Vue.jsの概要 おまけ 1 defineSlots()を使う コンポーネントの中に コンポーネントを動的に かつ、型付けした上で 差し込むこともできます。 ChildSlots.vue

Slide 18

Slide 18 text

18
 Vue.jsの概要 おまけ 2 index.vue defineSlots()を使う コンポーネントを呼び出す際 にtmplateのデータバイン ディングにも型が付与されて います。

Slide 19

Slide 19 text

19
 Vue.jsの概要 おまけ 3 defineSlots()を使う コンポーネントを呼び出す際 にtmplateのデータバイン ディングにも型が付与されて います。 index.vue

Slide 20

Slide 20 text

20
 Vue.jsコミュニティ発のツールチェインについて 1 主要なツール・フレームワーク - Nuxt(https://nuxt.com/)発音記号: /nʌkst/ - Vue.jsを利用したWebフレームワーク - Vite(https://ja.vitejs.dev/)発音記号: /vit/ - 次世代フロントエンドツール(高速に起動する開発サーバ, 高速なHMR, Rollup互換のプラグインシステム. etc) - Vitest(https://vitest.dev/)発音記号: /vitést/ - フロントエンドのテストフレームワーク - Pinia(https://pinia.vuejs.org/)発音記号: /piːnjʌ/ - TypeScriptフレンドリーな、Vue用の状態管理ツール Vuex正式な後継にあたる

Slide 21

Slide 21 text

21
 Vue.jsコミュニティ発のツールチェインについて 2 その他ツール - Volar.js(https://volarjs.dev/)発音記号: /bolaɾ/ - VueやAstroなどの組み込み型のフレームワーク用の言語ツール - vuejs/language-tools(https://github.com/vuejs/language-tools) - Volar.jsベースのVue用の言語ツール群 (vscodeのVue用のextensionsなどでも利用されています) - vue-i18n, eslint-plugin-vue, vuejs/core-vapor .etc 日本人含むアジア圏のメンテナ・コミッタも 数多く携わっていて情報も多い

Slide 22

Slide 22 text

22
 Vue.jsコミュニティ発のツールチェインについて 3 その他ツール - VitePress(https://vitepress.dev/)発音記号: [vitprés] - ViteとVueによる静的サイトジェネレータ - VueUse(https://github.com/vueuse/vueuse) - Composablesをまとめたライブラリ - Histoire(https://histoire.dev/)発音記号: [is.twaʁ.] - StorybookのようなVue/Svelte用のUIツール - vue-router(https://router.vuejs.org/) - vue-test-utils(https://test-utils.vuejs.org/)

Slide 23

Slide 23 text

23
 Vue.jsのTypeScript対応の経緯について 1 Vue2(Options API)の頃は... - Vueコンポーネントのロジックのみを外部ファイルに分割しづらい => mixinという機能はあったが型の恩恵を受けられない... - 状態管理ツールなどから型が渡ってこない => Storeを利用した時点で型の恩恵を受けづらくなる... - thisやテンプレートに型の反映がされない(Props, Emits .etc) => コンポーネント間のデータのやりとりなどが追いづらい... .etc まるっと解決できる  魔法の機能がほしい!!

Slide 24

Slide 24 text

24
 銀の弾丸はない

Slide 25

Slide 25 text

25
 Vue.jsのTypeScript対応の経緯について 2 Vue.jsのTypeScript対応の過程 1. Composition API の登場 2. コンポーネントランタイムの型付けが改善する 3. Volar.jsとvuejs/language-toolsによりエディタへの型反映の 問題が改善する

Slide 26

Slide 26 text

26
 Vue.jsのTypeScript対応の経緯について 3 1. Composition APIの登場 - Composition API は Vueコンポーネントを構成するための 関数ベースのAPIセットの総称 [1] - Reactivity API(ref, computed) - Lifecycle Hooks(onMounted, onUnmounted) - Dependency Injection: 依存性注入(inject, provide) - Vueコンポーネントのロジックのみを外部ファイルに分割しづらい => Composables として切り出すことが可能になり型付けも改善 された [2] [1] https://ja.vuejs.org/guide/extras/composition-api-faq#what-is-composition-api, [2] https://ja.vuejs.org/guide/reusability/composables,

Slide 27

Slide 27 text

27
 Vue.jsのTypeScript対応の経緯について 4 1. Composition API によるTypeScriptとの親和性の恩恵 - 状態管理用のライブラリなどから型が渡ってこない [1] https://ja.vuejs.org/guide/extras/composition-api-faq#better-type-inference, [2] https://ja.vuejs.org/guide/typescript/composition-api.html#typing-provide-inject, => Options API 実装当初は型推論の考慮がされておらず、 コンポーネントランタイム と 今まで this で記述していた Reactivity API が紐づいていて柔軟な型付けが困難な状態だった => コンポーネントランタイム から関数ベースのReactivity API が 切り離されることで、カプセル化やモジュール化をしやすくなり TypeScriptフレンドリーに [1] => Provide/Injectなどの状態管理で利用する機能も型の恩恵を受ける ことが可能に [2]

Slide 28

Slide 28 text

28
 Vue.jsのTypeScript対応の経緯について 5 2. コンポーネントランタイムの型付けが改善される - this(コンポーネントのインスタンス)に型の反映がされない => 型推論付きのヘルパー関数である defineComponent() が 新たに実装されTypeScriptフレンドリーに [1] => Emitsにも型付けが可能に [2] Propsもユーティリティ型の PropTypeで型付け可能に [3] [1] https://ja.vuejs.org/api/general#definecomponent [2] https://ja.vuejs.org/api/utility-types#proptype-t [3] https://ja.vuejs.org/guide/typescript/composition-api.html#typing-component-emits,

Slide 29

Slide 29 text

29
 Vue.jsのTypeScript対応の経緯について 5 2. コンポーネントランタイムの型付けが改善される - defineComponent() の型付け(とても複雑) ref: https://github.com/vuejs/core/blob/c0c9432b64091fa15fd8619cfb06828735356a42/packages/runti me-core/src/apiDefineComponent.ts#L44

Slide 30

Slide 30 text

30
 Vue.jsのTypeScript対応の経緯について 5 2. コンポーネントランタイムの型付けが改善される - defineComponent() の型付け

Slide 31

Slide 31 text

31
 3. Volar.jsとvuejs/language-toolsの功績 - テンプレートに型の反映がされない [1] Vue Language Server から生まれた Volar.js と、それが秘める可能性 , mizdra https://speakerdeck.com/mizdra/vue-language-server-karasheng-mareta-volar-dot-js-to-soregami-meruke-neng-xing, Vue.jsのTypeScript対応の経緯について 6 => コンポーネントランタイムのTypeScript対応が終わっても 各エディタの言語ツールにそれらを適用する必要があり、 その問題がVolar.jsベースのlanguage-toolsにより解決される [1] この部分で複雑な問題を抱えていたことで 改善にかなりの時間を要した

Slide 32

Slide 32 text

32
 - Vue2の頃は、Veturというツールがありましたが、ランタイムの型付け がなされていない問題や様々な問題によりTypeScript対応が未熟だった [1] - Vue.js Language Feature(Volar) 2年を費やし型付けが大きく改善 [2] - Volar のコアが Volar.js に切り出される。同時に Vue固有の実装は vuejs/language-tools へ移動され、IDEでもサポート可能に [3] - Volar.js は Astro や MDX など他の組み込みフレームワークでも利用可能で実 際に利用されている 3. Volar.jsとvuejs/language-toolsの功績の詳細 [1] https://github.com/vuejs/vetur, Vue.jsのTypeScript対応の経緯について 7 [2] Volar New Breaking, Johnson chu https://volarjs.dev/blog/volar-a-new-beginning/, [3] https://marketplace.visualstudio.com/items?itemName=Vue.volar

Slide 33

Slide 33 text

33
 3. Volar.jsとvuejs/language-toolsの功績の詳細 - vue-tsc を使って確認できる [1] Vue.jsのTypeScript対応の経緯について 8 [1] https://www.npmjs.com/package/vue-tsc,

Slide 34

Slide 34 text

34
 3. Volar.jsとvuejs/language-toolsの功績の詳細 - vue-tsc を使って確認できる [1] Vue.jsのTypeScript対応の経緯について 8 [1] https://www.npmjs.com/package/vue-tsc,

Slide 35

Slide 35 text

35
 Options API は今後も利用して問題ない - 今まで通りに直感的な開発が可能である - 小中規模アプリケーションでは、Options APIでスピードを持って開発 するような場面が想定される - 前述した改善により Options API でもある程度の柔軟な型付けが可能 になっている - Vue3 になってからも引き続きOptions APIを利用でき、廃止される予定は ないと明記されている [1] [1] https://vuejs.org/guide/extras/composition-api-faq#will-options-api-be-deprecated Composition API に 引け目を感じなくてもOK!! Vue.jsのTypeScript対応の経緯について 9

Slide 36

Slide 36 text

36
 ref: Vue Fes Japan 2023, Evan You キーノート https://www.youtube.com/watch?v=QkhLzoEwvwM Vue.jsのTypeScript対応の経緯について 追記 Vue.jsは Vue2 からVue3 への 大きな変更による影響を反省し、 今後のマイグレーションを慎重に行っていく

Slide 37

Slide 37 text

37
 具体的にはどうなったの?

Slide 38

Slide 38 text

38
 状態管理と型 1 Composablesとして、 Vueコンポーネントから ロジックと状態を外部に 切り出すことが可能になり ました。 pages/index.vue

Slide 39

Slide 39 text

39
 状態管理と型 1 Composablesとして、 Vueコンポーネントから ロジックと状態を外部に 切り出すことが可能になり ました。 pages/index.vue composables/useCounter.ts

Slide 40

Slide 40 text

40
 状態管理と型 1 Composablesとして、 Vueコンポーネントから ロジックと状態を外部に 切り出すことが可能になり ました。 pages/index.vue composables/useCounter.ts

Slide 41

Slide 41 text

41
 状態管理と型 2 composables/useCounter.ts readonlyを利用した、 関数によるカプセル化 によってより保守性が 高まりますね。

Slide 42

Slide 42 text

42
 状態管理と型 3 状態を複数コンポーネント間で またぐこともできます。 composables/useCounter.ts しかし、このままではSSR時 にうまく動作しなかったり、 状態管理が複雑化してしまう 問題があります。

Slide 43

Slide 43 text

43
 Piniaを利用しよう

Slide 44

Slide 44 text

44
 Piniaを利用しよう defineStore()でキーと Composition APIを 使ってComposables のように書くことが できます。 状態管理と型 4 stores/useCounter.ts

Slide 45

Slide 45 text

45
 Piniaを利用しよう defineStore()でキーと Composition APIを 使ってComposables のように書くことが できます。 状態管理と型 4 stores/useCounter.ts

Slide 46

Slide 46 text

46
 Piniaを利用しよう 利用したい先で、 useCounterStore() を呼び出す。 よしなにカプセル化 されているため、 Store上で定義された countも直接の 書き換えができない ようになっています。 状態管理と型 4 a pages/index.vue

Slide 47

Slide 47 text

47
 Piniaを利用しよう 利用したい先で、 useCounterStore() を呼び出す。 よしなにカプセル化 されているため、 Store上で定義された countも直接の 書き換えができない ようになっています。 状態管理と型 4 a pages/index.vue

Slide 48

Slide 48 text

48
 状態管理と型 5 Provide/Injectを利用した発展的な状態管理 Piniaはグローバルスコープですが、Provide/Injectを使うと スコープを制限した状態管理が可能です。 ref: https://ja.vuejs.org/assets/provide-inject.C0gAIfVn.png

Slide 49

Slide 49 text

49
 状態管理と型 6 TypeScriptフレンドリーに実現する場合 1. SymbolをInjectionKeyとして定義し、定義したSymbolに対して、 ユーティリティ型のInjectionKeyを利用し型付けする 2. データを伝搬させたいコンポーネントが含まれている ルートコンポーネントで定義したProvideを呼び出す (スコープの指定が可能) 3. データが必要なコンポーネント内でInjectionKeyを利用しデータを 取得する

Slide 50

Slide 50 text

50
 Provide/Injectと型の利用 1. app.vue(Root)などの script内で関数を呼び 出してprovideする 2. データを呼び出したい 先でInjectionKeyを 利用しインジェクション する 状態管理と型 7 useProviderCounter.ts

Slide 51

Slide 51 text

51
 Provide/Injectと型の利用 1. app.vue(Root)などの script内で関数を呼び 出してprovideする 2. データを呼び出したい 先でInjectionKeyを 利用しインジェクション する 状態管理と型 7 useProviderCounter.ts pages/index.vue

Slide 52

Slide 52 text

52
 Provide/Injectと型の利用 1. app.vue(Root)などの script内で関数を呼び 出してprovideする 2. データを呼び出したい 先でInjectionKeyを 利用しインジェクション する 状態管理と型 7 useProviderCounter.ts pages/index.vue

Slide 53

Slide 53 text

53
 型を利用してデータフローを可視化しよう 1 ユーザーデータの取得例で考える 1. IDに紐づくユーザーのデータを取得できるAPIを利用します。 2. APIは、IDとパスワードをPOSTリクエストのボディにセットする 必要があります。 3. 取得したデータは複数のページコンポーネントで利用したいので グローバルステートとして保持する必要があります。 4. 一連のデータフローを型で表現します。

Slide 54

Slide 54 text

54
 型を利用してデータフローを可視化しよう 2 ファイル構成 GitHub: https://github.com/tsukuha/vue-sample-tskaigi

Slide 55

Slide 55 text

55
 型を利用してデータフローを可視化しよう 3 シーケンス図

Slide 56

Slide 56 text

56
 型を利用してデータフローを可視化しよう 4 まずAPIから作成する IOの部分から型付けする ことで、データの終わり と始まりが明確に。 レスポンスの型定義も このときにexportする と便利になります。 api/user.ts

Slide 57

Slide 57 text

57
 型を利用してデータフローを可視化しよう 5 Storeを用意する APIで定義したレスポンス の型とStoreを紐付ける ことで一貫性のあるデータ フローを型で表現します。 Storeで状態とロジック をカプセル化することで 何のStoreかも明確に。 store/user.ts

Slide 58

Slide 58 text

58
 型を利用してデータフローを可視化しよう 6 Storeを用意する APIで定義したレスポンス の型とStoreを紐付ける ことで一貫性のあるデータ フローを型で表現します。 Storeで状態とロジック をカプセル化することで 何のStoreかも明確に。 store/user.ts

Slide 59

Slide 59 text

59
 コンポーネントで利用する コンポーネントのロジックで 必要なStoreを呼び出す ことによって、APIから 受け取る予定のデータが 型によって表現できます。 型を利用してデータフローを可視化しよう 6 pages/index.vue

Slide 60

Slide 60 text

60
 コンポーネントで利用する コンポーネントのロジックで 必要なStoreを呼び出す ことによって、APIから 受け取る予定のデータが 型によって表現できます。 型を利用してデータフローを可視化しよう 6 pages/index.vue

Slide 61

Slide 61 text

61
 コンポーネントで利用する テンプレートにもAPI、 Storeと渡ってきた 型が反映されていて きちんと型付けでき ていることがわかり ます。 型を利用してデータフローを可視化しよう 7 pages/index.vue

Slide 62

Slide 62 text

62
 コンポーネントで利用する テンプレートにもAPI、 Storeと渡ってきた 型が反映されていて きちんと型付けでき ていることがわかり ます。 型を利用してデータフローを可視化しよう 7 pages/index.vue

Slide 63

Slide 63 text

63
 - Vue.jsのTypeScript対応は複雑な経緯を辿った - Composition APIの登場 - コンポーネントランタイムの型付け - Volar.jsとvuejs/language-toolsの功績 - 具体的な例を通してTypeScriptとの親和性を理解する - 親子コンポーネントとの対話例 - 状態管理の例 - 具体的なユースケースを利用した例 おわりに

Slide 64

Slide 64 text

64
 Vue.jsはすでに  TypeScriptフレンドリーです!!

Slide 65

Slide 65 text

65
 Vue.jsのその他資料 Vueコンポーネントのライフサイクルについて - https://ja.vuejs.org/guide/essentials/lifecycle SFC(Single Function Coponent)構文仕様 - https://ja.vuejs.org/api/sfc-spec.html Composition APIとOptions API どちらを選ぶか - https://ja.vuejs.org/guide/introduction#which-to-choose