🐡

Migrating Vue 2 to Vue 3

5 min read

初めに

公式サイトでは Vue3 の使い方や破壊的変更点などを列挙されています。

しかしながら知りたいのは Vue2 から Vue3 に移行する手順やツールですよね。

vuejs-jp の slack で質問したところ vue-codemod というツールがあるそうです。
Vue 3 migration helper は現在開発中とのこと。
(じゃあこの記事要らない…?)

公式Twitterで公表されたので、この記事の命はあとわずか…(5/1現在)
https://twitter.com/vuejs/status/1388144585600274433?s=21

この記事では マニュアルでの 2021/4/21 現在での Vue2 から Vue3 への移行手順を残すことにしました。

Vue3 へ移行する前段階としては eslint-plugin-vue の v7 を入れて Vue3用の設定 を導入し、エラーが消えるまで対応することをお勧めします。

結果はこちら

https://github.com/shippokun/migration-vue3

前提

VueCLI で Vue2 を作成した状態からスタートします。
基本的な Vue.js によって作られたプロジェクトは下記の構成+外部ライブラリで満たせると思っています。
Vue.js に依存したライブラリを使用している場合は、 Vue3 に対応しているのかどうかの調査が必須ですので、移行を検討する際には必ず確認しましょう。

Vue CLI v4.5.12
? Please pick a preset: Manually select features
? Check the features needed for your project: Choose Vue version, Babel, TS, Rou
ter, Vuex, CSS Pre-processors, Linter, Unit
? Choose a version of Vue.js that you want to start the project with 2.x
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass)
? Pick a linter / formatter config: Prettier
? Pick additional lint features: Lint on save
? Pick a unit testing solution: Jest
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N)

手順

0. 不要なライブラリの削除

Vue.js では vue-class-componentvue-property-decorator など、さまざまなコンポーネントの記述方法があります。どの記述方式を選ぶのかはそれぞれ選定基準があり難しいですが、 TypeScript を使用するのなら公式サイトにもあるように2種類の記述方式のどちらかを選択するのがよいと考えています。

  1. OptionsAPI
  2. CompositionAPI

どちらも Vue3 では import { defineComponent } from 'vue'; で使用することが可能なので冒頭で挙げたライブラリはアンインストールしても問題はないです。

また vue-template-compiler は Vue2 用のライブラリなので削除します。

https://www.npmjs.com/package/vue-template-compiler

This package can be used to pre-compile Vue 2.0 templates into render functions to avoid runtime-compilation overhead and CSP restrictions. In most cases you should be using it with vue-loader, you will only need it separately if you are writing build tools with very specific needs.

npm uninstall vue-class-component vue-property-decorator vue-template-compiler

1. アップデート&インストール

本命のアップグレードです。
単純に Vue, Vuex, VueRouter をアップデートすればいいと思っていたのですが、 jest 周りで怒られてしまったので jest のアップデートを行い、そのあと行頭のライブラリをアップデートしました。[1]

npm i -D vue-jest@next @vue/test-utils@next -f
npm i vue@next vuex@next vue-router@next -f
npm i -D @vue/compiler-sfc

2. 型定義の更新

Vue2 でプロジェクトを作成すると src/shims-tsx.d.tssrc/shims-vue.d.ts が作成されます。前者は Vue2 で JSX を記述する必要ですが、 Vue3 では CompositionAPI の setup 関数自体が renderComponent を返すことができるので不要です。[2]
後者のみ下記の内容に書き換えました。参考元は Vue3 のプロジェクトを作成した際に発行されたコードです。[3]

src/shims-vue.d.ts
/* eslint-disable */
declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

3. Migrate of VueRouter

Vue3 ではプラグイン[4]のインストール方法が Vue2 とは異なります。
そのためプラグインが Vue3 に移行できるか否かが重要となってきます。
VueRouterも従来の記述方式とは要所要所が異なっているので注意しましょう。

src/router.ts
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";

// Vue.useは使わない。

// 型が変更。 RouteConfig → RouteRecordRaw
const routes: Array<RouteRecordRaw> = [
  // 省略
];

// new VueRouterではなく、 createRouter を使用する。また mode ではなく、 history で専用の関数が用意されているので、用途に合わせて使い分けをしましょう。
export const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes,
});

4. Migrate of Vuex

Vuex も VueRouter と同様です。
module や 更に getter や mutation など細部でも型定義をしたい場合は GetterTree などを使う必要があります。

src/store.ts
import { createStore } from "vuex";

// new Vuex.Storeではない。
export const store = createStore({})

より詳細に書きたい場合は参考までに

https://github.com/shippokun/todo-vue3/tree/main/src/store

5. Migrate of Vue

プラグインのマイグレーションを終えたらようやくエントリーファイルである main.ts の書き換えです。
コード自体は下記のみです。
注意する点としては使用できるプラグインは createApp で use できるもののみとなっていることです。

src/main.ts
import { createApp } from "vue";
import App from "./App.vue";
import { router } from "./router";
import { store } from "./store";

createApp(App).use(store).use(router).mount("#app");

6. Componentの書き換え

Vue2 のデフォルトのプロジェクトは 0. 不要なライブラリの削除 でアンインストールしたクラスコンポーネントの記法で記述されています。それらのコンポーネントを全て OptionsAPI か CompositionAPI に書き換えたら Vue3 へのマイグレーションは終了です。

<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({})
</script>

まとめ

Vue2 から Vue3 へのマイグレーションはさまざまな破壊的変更があり、やはりスムーズに移行するのは難しいです。
しかしながら Vue3 で得られる恩恵も多く、特に TypeScript まわりのサポートは Vue2 よりも断然高くなっています。(TSX で書けるようになっているのは大きい)
また今まで負債になりやすかった mixins や filter の非推奨化である程度メンテナンスしやすいものになっていくのではと期待しています。[5]

Vue3 へマイグレーションを検討している人の参考になれば幸いです。

脚注
  1. もしかしたら -f オプションをつけるだけでいけたかもしれないです。未確認。 ↩︎

  2. TSX についてはこちらで書いています。 ↩︎

  3. 適切な参考元を知っていたら教えていただけると助かります。 ↩︎

  4. Vueに関連するライブラリをプラグインと指しています。VueRouterやVuex、Vuetifyなど。 ↩︎

  5. mixinsは非推奨ではなく、CompositionAPIという手段があるよ、と提示されているだけなので語弊。 ↩︎

Discussion

ログインするとコメントできます