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

Migrating to Vue 2.7 for safe and improve development efficiency / 安全に開発効率を上げるための Vue_2.7 移行

watsuyo_2
May 25, 2023
200

Migrating to Vue 2.7 for safe and improve development efficiency / 安全に開発効率を上げるための Vue_2.7 移行

At iCARE, Inc., I presented the following content regarding our plan to migrate our products developed with Vue 2.6 to Vue 3, with an intermediate step through Vue 2.7.

1. Why did we choose Vue 2.7 as an intermediate step instead of directly migrating to Vue 3?
2. The benefits and reduced risks achieved by transitioning through Vue 2.7.
3. Necessary considerations to achieve version migration without compromising development speed in a fast-paced environment.
4. The estimated cost of migrating from Vue 2.6 to Vue 2.7.
5. The cost-effectiveness analysis of the migration.
6. Reflections and lessons learned from the migration process.

株式会社 iCARE では、Vue 2.6 で開発しているプロダクトを、 Vue 2.7 を経由してから Vue 3 に移行する計画を立てました。
以下の内容を発表します。

なぜ移行先は Vue 3 でなく、Vue 2.7 を選んだのか
Vue 2.7 を経由することによって軽減される負担とリスク
開発スピードを落とせない環境下で、バージョン移行を実現するために必要なこと
Vue 2.6 から Vue 2.7 への移行コストはどれくらいなのか
移行の費用対効果
移行の感想と反省

watsuyo_2

May 25, 2023
Tweet

Transcript

  1. 安全に開発効率を上げるための Vue 2.7 移行
    watsuyo
    2022/10/16, VueFes 2022
    watsuyo 2022/10/16, VueFes 2022 1 / 36

    View full-size slide

  2. 本セッションの実況、感想、Vue 2.7 移行の意見交換は 👇
    Twitter: watsuyo_2 👆
    #vuefes
    🍣 🍖 🍜
    watsuyo 2022/10/16, VueFes 2022 2 / 36

    View full-size slide

  3. 本セッションのスライドは、Slidev で作成しました
    watsuyo 2022/10/16, VueFes 2022 3 / 36

    View full-size slide

  4. 自己紹介
    watsuyo 2022/10/16, VueFes 2022 4 / 36

    View full-size slide

  5. 自己紹介
    GitHub: watsuyo
    Twitter: watsuyo_2
    仕事: 株式会社 iCARE 2020年10月〜
    Carely のフロントエンドを Vue.js や TypeScript で実装
    8月からは、PjM としてプロジェクト管理も
    学び: 東京都立産業技術大学院大学・情報アーキテクチャ
    コース 2021年4月〜
    趣味:
    野球観戦
    焼肉
    寿司
    ラーメン
    watsuyo 2022/10/16, VueFes 2022 5 / 36

    View full-size slide

  6. 「話すこと」 と 「前提」
    watsuyo 2022/10/16, VueFes 2022 6 / 36

    View full-size slide

  7. 「話すこと」 と 「前提」
    話すこと
    Vue 3 と Vue 2.7 違い
    Vue 2.6 から Vue 2.7 へ移行した話
    開発しているプロダクトを Vue 3 には上げられないけど、少しでも新しい Vue の機能を使いたい人が、Vue 2.7 に移行したくなる話
    Vue 2.7 移行の助けになる話
    前提 ※
    SPA ではなく、ルーティングが Ruby on Rails に依存した MPA である
    外部ライブラリに対する依存度の影響で、Vue 3 移行へのコストが高い
    Vue 2.7 移行前までは、Vue 2.6 + @vue/composition-api を利用し、defineComponent の setup() を使った実装をしていた
    Vue 2.7 に移行したあとも、defineComponent の setup() を使用している

    Carely の開発において
    watsuyo 2022/10/16, VueFes 2022 7 / 36

    View full-size slide

  8. Vue 2.7 がリリースされるまでの流れ
    watsuyo 2022/10/16, VueFes 2022 8 / 36

    View full-size slide

  9. Vue 2.7 がリリースされるまでの流れ
    2020年に Vue 3 がリリースされたときから、Vue 2.7 のリリースは予告されていた
    「Vuejs Amsterdam 2022」の Evan You さんの講演で、Vue 2.7 の概要とリリース日が発表された
    2022/05/31 に、 v2.7.0-alpha.1 がリリースされた
    Carely においては、v2.7.0-alpha から、継続的に Vue 2.7 移行の手順を模索し、v2.7 の正式リリースまでに Vue.2.7 移行を進めた
    2022/07/01 に、Vue 2.7 が正式リリースされた
    Carely は、2022/09/01 に Vue 2.7 へ移行完了
    watsuyo 2022/10/16, VueFes 2022 9 / 36

    View full-size slide

  10. Vue 2.7 の概要
    watsuyo 2022/10/16, VueFes 2022 10 / 36

    View full-size slide

  11. Vue 2.7 の概要
    概要
    Vue 2、最後のマイナーバージョン
    Vue 2 を使用しているプロダクトにとって Vue 3 移行のためのバージョンである
    2023年末で EOL を迎える
    バックポート機能
    Composition API
    <br/>CSS v-bind<br/>参考: Vue 2.7 "Naruto" Released<br/>watsuyo 2022/10/16, VueFes 2022 11 / 36<br/>

    View full-size slide

  12. Vue 3との違い
    watsuyo 2022/10/16, VueFes 2022 12 / 36

    View full-size slide

  13. Vue 3との違い
    リアクティビティ
    Vue2.7 の Composition API では、レガシーブラウザとの互換性を保つために、Vue 2.6 以前と同様に、Getter / Setter がベースのリアクティビ
    ティが使用されている
    基本的には、Vue 2 のリアクティビティシステムと同じである(v2 ドキュメント)
    Vue3 では、ES6 から導入された Proxy をベースのリアクティビティシステムが使用されている
    参考: Vue 2.7 "Naruto" Released
    watsuyo 2022/10/16, VueFes 2022 13 / 36

    View full-size slide

  14. Vue 3との違い
    バックポートされない機能
    createApp()
    <br/>直下での await<br/>template 内での TypeScript 構文のサポート<br/>Reactivity transform<br/>expose オプション<br/><setup script><br/>で、 defineExpose() は使える<br/>参考: Vue 2.7 "Naruto" Released<br/>watsuyo 2022/10/16, VueFes 2022 14 / 36<br/>

    View full-size slide

  15. Vue 2.7 を経由するメリット と 注意点
    watsuyo 2022/10/16, VueFes 2022 15 / 36

    View full-size slide

  16. Vue 2.7 を経由するメリット
    Vue 3 の機能がバックポートされるため、段階的に移行できる
    また、移行の負担とリスクが軽減される
    Composition API [変更]、Vite [新規]、Volar [変更]、context.root
    [廃止] を Vue 3 に先立って、対応・導入できる
    動作確認のコストを削減できる
    影響範囲の切り分けがしやすい
    安全にバージョン移行できる確率が高まる
    Vue 2.7 と Vue 3 のように、2つのマイルストーンを置くことで、
    難しい issue を分割し、エンジニアの負担を軽減できる
    watsuyo 2022/10/16, VueFes 2022 16 / 36

    View full-size slide

  17. Vue 2.7 を経由する注意点
    @vue/composition-api との一貫性が保証されていない
    @vue/composition-api は、すでににメンテナスモードに入っており、2022年末で EOL になる予定
    Vue 3 の機能を網羅しているわけではない
    v-model:value も使えないし、<br/>も完全には使えない<br/>1. Breaking change vue 2.7.8 with vue-composition-api 1.7.0 #12752↩︎<br/>2. CHANGELOG.md#270-2022-07-01↩︎<br/>[1]<br/>[2]<br/>watsuyo 2022/10/16, VueFes 2022 17 / 36<br/>

    View full-size slide

  18. 段階的に Vue のバージョアップが必要な理由
    watsuyo 2022/10/16, VueFes 2022 18 / 36

    View full-size slide

  19. 段階的に Vue のバージョアップが必要な理由
    Vue 2 の 2023 年末に EOL を迎える
    長期的には Vue や 外部パッケージ に セキュリティリスクが含まれてしまった場合、急な対応が難しくなる
    2023 年末は、残り約 14 ヶ月 🚨
    watsuyo 2022/10/16, VueFes 2022 19 / 36

    View full-size slide

  20. Vue 2.7 移行のつまずきポイント
    watsuyo 2022/10/16, VueFes 2022 20 / 36

    View full-size slide

  21. Vue 2.7 移行のつまずきポイント
    Vue Instance 参照方法の変更
    emit を関数へ渡すときの型の注意点
    Error: Avoid using variables that start with _ or $ in setup()
    watsuyo 2022/10/16, VueFes 2022 21 / 36

    View full-size slide

  22. Vue Instance 参照方法の変更
    watsuyo 2022/10/16, VueFes 2022 22 / 36

    View full-size slide

  23. Vue Instance 参照方法の変更
    vuejs/composition-api/src/runtimeContext.ts vuejs/vue/src/v3/apiSetup.ts
    @vue/composition-api(左) で @deprecated なプロパティは、Vue
    2.7(右) から削除されている
    root が無くなったことで、Vue Instance プロパティに依存するメソ
    ッドが、SetupContext から呼び出せなくなった
    1. vuejs/composition-api/src/runtimeContext.ts#L148-L176↩︎
    2. vuejs/vue/src/v3/apiSetup.ts#L20-L26↩︎
    [1]
    export interface SetupContext {

    attrs: Data

    slots: Slots

    emit: EmitFn

    /**

    * @deprecated not available in Vue 2

    */

    expose: (exposed?: Record) => void

    /**

    * @deprecated not available in Vue 3

    */

    readonly parent: ComponentInstance | null

    /**

    * @deprecated not available in Vue 3

    */

    readonly root: ComponentInstance

    /**

    * @deprecated not available in Vue 3

    */

    readonly listeners: { [key in string]?: Function }

    /**

    * @deprecated not available in Vue 3

    */

    readonly refs: { [key: string]: Vue | Element | Vue[] | Element[] }

    }
    [2]
    export interface SetupContext {

    attrs: Data

    /**

    * Equivalent of `this.$listeners`, which is Vue 2 only.

    */

    listeners: Record

    slots: Slots

    emit: EmitFn

    expose(exposed?: Record): void

    }
    watsuyo 2022/10/16, VueFes 2022 23 / 36

    View full-size slide

  24. Vue Instance 参照方法の変更
    vuejs/core/packages/runtime-core/src/component.ts Vue 3 の場合も、Vue 2.7 同様に、@deprecated なプロパティは 削
    除されている
    また、listeners も削除されている
    1. vuejs/core/packages/runtime-core/src/component.ts#L182-L187↩︎
    [1]
    export interface SetupContext {

    attrs: Data

    slots: Slots

    emit: EmitFn

    expose: (exposed?: Record) => void

    }
    watsuyo 2022/10/16, VueFes 2022 24 / 36

    View full-size slide

  25. Vue Instance 参照方法の変更
    useGetProxy.ts index.vue
    getCurrentInstance()
    から Vue Instance を取得し、proxy 経由
    で root をを取得する独自のユーティリティ関数を実装した
    Vue コンポーネントからは getProxy() を呼び出すことで、利用でき

    また、現状の実装に依存しているプロパティだけを呼び出すため、
    型で制御している
    しかし、getCurrentInstance()
    は、Public API ではなく、ライ
    ブラリ開発者が利用するもので、本来の使い方ではないため、利用
    は推奨されていない
    また、Vue 3 の今後のアップデートでは、警告が出るようになり、
    互換性がなくなる可能性が指摘されている
    1. Evan You さんのコメント↩︎
    import Vue, { getCurrentInstance } from 'vue'

    export type VueProxyType = Pick

    const vueInstance = {

    root: {
    proxy: Vue as unknown as VueProxyType,

    },

    }

    type VueInstanceType = typeof vueInstance

    /**

    * internal vm
    の proxy
    を返す

    */

    export const getProxy = (): VueProxyType => {

    const instance =
    (getCurrentInstance() as unknown as VueInstanceType)?.root || getCurrentInstance()

    return instance?.proxy

    }
    import { getProxy } from '@/environment/useGetProxy'

    export default defineComponent({

    setup(_, { emit, slots}) {

    const root = getProxy()

    const { $buefy, $apollo, $el, $refs } = root

    }

    })
    [1]
    watsuyo 2022/10/16, VueFes 2022 25 / 36

    View full-size slide

  26. emit を関数へ渡すときの型の注意点
    watsuyo 2022/10/16, VueFes 2022 26 / 36

    View full-size slide

  27. emit を関数へ渡すときの型の注意点
    Vue 2.6 以前 Vue 2.7 以降
    SetupContext から取得できる emit 型が Vue 2.7 で変更された
    defineComponent の emits: [] フィールドで指定する event 名が T に入る
    どの event に対応した emit が受け取れるのかを明示する必要がある
    emit: (event: string, ...args: any[]) => void emit: (event: T, ...args: any[]) => void
    watsuyo 2022/10/16, VueFes 2022 27 / 36

    View full-size slide

  28. emit を関数へ渡すときの型の注意点
    emit-function-type.ts
    event の型を捕捉するため、EmitFunctionType という ジェネリック
    型を定義する
    例えば、func() の引数に emit を渡したい場合は、
    EmitFunctionType<'close'> のように型定義する
    func.ts
    EmitFunctionType を利用して、event 名を含む emit しか受け付けないように
    する
    export type EmitFunctionType = (

    event: T,

    ...args: any[]

    ) => void
    export const func = (

    emit: EmitFunctionType<'close'>

    ) => {

    ...

    emit('close')

    ...

    }
    watsuyo 2022/10/16, VueFes 2022 28 / 36

    View full-size slide

  29. Error: Avoid using variables that start with _ or $ in setup()
    watsuyo 2022/10/16, VueFes 2022 29 / 36

    View full-size slide

  30. Error: Avoid using variables that start with _ or $ in setup()
    Carely では、一部のコンポーネントで、_ 始まりの変数が定義されていた
    以前から、Vue 内部のプロパティで、_ や $ が予約語となっており、データバインディングでは使用できないとされていた
    しかし、Vue2.6 で開発を行っているときには、問題となっていなかった
    Vue 2.7 にアップデートしたタイミングで、v-modal を使ってバインディングしている箇所でフォームに input した値が変数に保存されな
    い問題が発生した
    1. Evan You さんのコメント↩︎
    [1]
    watsuyo 2022/10/16, VueFes 2022 30 / 36

    View full-size slide

  31. Error: Avoid using variables that start with _ or $ in setup()
    Vue 2.6 + @vue/composition-api と Vue 3 では、_inputValue へ入力
    した値が保存される
    Vue 2.7 だけ、変数の頭文字を $ か _ にしていると、_inputValue へ
    入力した値が保存されない
    Vue.js 側で、 console に警告が出るように実装されている
    CodeSandbox
    Vue3
    Vue2.6 + @vue/composition-api
    Vue2.7










    {{ _inputValue }}







    <br/><br/>// Vue 2.6 + @vue/composition-api<br/><br/>import { defineComponent, ref } from "@vue/composition-api";<br/><br/>// Vue 2.7 | Vue 3<br/><br/>import { defineComponent, ref } from "vue";<br/><br/>export default defineComponent({<br/><br/>name: "App",<br/><br/>setup() {<br/><br/>const _inputValue = ref("");<br/><br/>return {<br/><br/>_inputValue,<br/><br/>};<br/><br/>},<br/><br/>});<br/><br/>
    watsuyo 2022/10/16, VueFes 2022 31 / 36

    View full-size slide

  32. Error: Avoid using variables that start with _ or $ in setup()
    vuejs/vue/src/core/util/lang.ts vuejs/vue/src/v3/apiSetup.ts
    1. vuejs/vue/src/core/util/lang.ts#L9-L15↩︎
    2. vuejs/vue/src/v3/apiSetup.ts#L62-L66↩︎
    [1]
    /**

    * Check if a string starts with $ or _

    */

    export function isReserved(str: string): boolean {

    const c = (str + '').charCodeAt(0)

    return c === 0x24 || c === 0x5f

    }
    [2]












    ...
    if (!isReserved(key)) {
    proxyWithRefUnwrap(vm, setupResult, key)
    } else if (__DEV__) {
    warn(`Avoid using variables that start with _ or $ in setup().`)
    }
    ...
    watsuyo 2022/10/16, VueFes 2022 32 / 36

    View full-size slide

  33. 番外編: Vue 2.7 移行の振り返り
    watsuyo 2022/10/16, VueFes 2022 33 / 36

    View full-size slide

  34. 番外編: Vue 2.7 移行の振り返り
    今後の大規模リリースに向けて、KPT 法による振り返りを
    開催
    参加者: @watsuyo、 @ozu_syo さん、 @oreo2991 さ

    今後のライブラリや言語のバージョンアップなどによる大規模リリ
    ースへの知見として、振り返りを行った
    watsuyo 2022/10/16, VueFes 2022 34 / 36

    View full-size slide

  35. 番外編: これから Vue 2.7 移行を行う方へ
    watsuyo 2022/10/16, VueFes 2022 35 / 36

    View full-size slide

  36. 番外編: これから Vue 2.7 移行を行う方へ
    感想、質問、Vue 2.7 移行の意見交換は👇
    Twitter: watsuyo_2 👆
    #vuefes
    🍣 🍖 🍜
    -
    コミットごとに手順書を書くことで、大量の差分があるコミットでも、どんな事をしたコミットなのかを明確にする

    -
    フロントエンドエンジニアメンバーに動作確認をお願いし、分担して行う

    - QA
    チームと連携して、動作確認を開発者とQAE
    のどちらがやるのかを話し合う

    -
    リリース後に各作業ブランチに取り込んだ後に動作確認してもらうことをアナウンスや事前告知を行う

    - Vue
    のコードを読む(composition-api
    と vue 2.7
    の差分を)

    -
    型定義を読めば気づけた仕様変更があったので、早めに読み始める

    -
    事前にリリースできるものを分割して、先に出しておくことでリスク軽減させる

    -
    もう少し早く着手できたらよかった

    - PR
    は何度も作り直して、できるだけアップデートに関係のない変更は先にリリースしておく

    -
    特に型エラーや、Lint
    エラーは事前に潰しておくと良い

    - CI
    で diff
    しかチェックしていない job
    は、設定ファイルをコメントアウトして置くのもあり

    -
    後でコメントアウトを戻すのを忘れずに

    - GitHub
    以外に、Twitter
    や Reddit
    、各ライブラリのコミュニティ (Slack
    や Discord)
    に情報も確認する
    watsuyo 2022/10/16, VueFes 2022 36 / 36

    View full-size slide