Vue2からVue3へ書き直す際に情報が不足していて困ったのでまとめておきます。
公式ドキュメント
まだversion3の公式ドキュメントは揃っていません。マージされたPRかRFCを見るしかない状況です。
migrate from v2 to v3
※「これだけ押さえれば7割くらいは移行できるだろう」くらいで網羅的には書けておりません
new Vue
によるインスタンス生成はcreateApp()
へと置き換え- setupメソッドの引数の型推論をしたい場合はSFCのexportするオブジェクトをdefineComponentでラップ
new Vue
のdataやmethodsはinject()
とapp.provide()
を使ってグローバルステートで置き換え React Context APIのようなもので、書き方もだいたい同じ。- watchやdata、computed、mountedなどほとんどのプロパティは消えてsetupへ集約
vue-template-compiler
の代わりに@vue/compiler-sfc
を使う- shims-vue.d.ts(SFCの型定義ファイル)の書き方が変わる
- render関数の引数として渡されていたh関数はグローバルインポート
インストール
バージョンは2020年6月19日現在のものです。
- vue@3.0.0-beta.15
SFCで書きたい、webpackを使いたいのであれば以下も必要です。
- vue-loader@16.0.0
- @vue/compiler-sfc@3.0.0-beta.15
- webpack, webpack-cli
書き方
大きく異なる点がいくつかあります
- composition APIが使える
- webpackのalias設定がいらなくなる
new Vue
が消える- Vueオブジェクトに生えていたAPIがnamed exportsオンリーになる
- TypeScriptとの親和性が高くなる
composition APIが使える
まずこれがかなり大きいです。このお陰でVueへもTypeScriptを導入しやすくなりました。this関連でひどい目に合わずに済むのは大変嬉しいです。
また、書き方もかなり楽になりました。ロジックを外へ抽出できるようになった点も嬉しいです。ReactのHooksとできることはほぼ同じですが、かなりVueらしいやり方に収まった感覚があり、とても好きです。
webpackのalias設定がいらなくなる
new Vue
の代わりにcreateApp
というメソッドを使ってマウントするようになりました。そのため、vue/dist/vue.esm.js
へエイリアスを張らなくて良くなります。逆に、Vue2の頃のaliasがwebpack.config.jsに残っているとビルドが失敗します。
createApp
こいつが結構やっかいです。従来のやりかたと所々異なっています。
rfcs/0009-global-api-change.md at 9f18645a700f54e7d9a4e3b53046d48791e31459 · vuejs/rfcs · GitHub
上記リンク先を見ていただけばわかりますが、ほとんどは同じです。しかし、たとえば下のようなケースでは若干変わってきます。
// v2 new Vue({ render: (h) => h(MyComponent, { props: { prop1, prop2 }, }) })
// v3 const app = createApp(MyComponent, { prop1, prop2 });
僕はかなり泥沼にハマりました。
defineComponentについて
setupのpropで型推論を働かせたいときにはdefineComponentでラップする必要があります。逆に、setupでpropを参照しないのならdefineComponentで囲む必要はなく、従来のSFCの書き方で十分です。
公式にも書いてありますが、defineComponent自体は受け取ったオブジェクトをただ返すだけの関数で、型推論以外では1ミリも役に立ちません。
Note that implementation-wise defineComponent does nothing - it simply returns the object passed to it. However, in terms of typing, the returned value has a synthetic type of a constructor for manual render function, TSX and IDE tooling support. This mismatch is an intentional trade-off.
JSXについて
renderのなかでJSXを使えるようになりました(今まではh関数を使ったcreateElement的な書き方しかできなかった)。これでvueファイルの中の<template>
を消してJSオンリーでかけるようになりました。
Global APIのnamed exports化
tree-shakingのための変更です。Vue以下に生えていたVue.nextTick
などはnextTick
関数としてexportされるようになります。Vue.nextTickは使えなくなります。このように、Vue3には後方互換性のない変更があるので注意が必要です。
SFCの型定義が変わる
new Vue
によるインスタンス生成から変わった影響で、SFCの型定義もdefineComponentを使うものへ変わりました。
declare module "*.vue" { import { defineComponent } from "vue"; const component: ReturnType<typeof defineComponent>; export default component; }
従来の型定義はcreateAppの引数として使えないので注意してください。
参考: vue-next(Vue.js 3.0 wip)+ TypeScript + webpackでの開発環境を構築する - Qiita