個人のWebサービスをVue2系からVue3系にアップグレードしてみたので、やったこととかメモしておきます📝
基本的な流れとしては以下の記事を参考にさせていただきました🙇♂️
事前準備
plugin:vue/vue3-recommendedを有効化する
まずはeslint-plugin-vue
のvue3-recommended
を有効化して静的解析を行うとVue3で非推奨になったオプション等に警告を出してくれるので、以下の通り有効化して対応を行いました👮
"extends": [ "eslint:recommended", "plugin:vue/vue3-recommended",
Vue本体のアップデート
ライブラリの更新・不要なライブラリの削除
以下のような形で関連ライブラリの更新を行いました。
yarn add vue-jest@next @vue/test-utils@next @vue/compiler-sfc vue-jest@next --dev yarn add vue@next
またVueの更新により不要となった以下のライブラリはpackage.json
から削除しました。
- vue-template-compiler
- @vue/composition-api
型定義の更新
参考記事の通り以下のようにVueの型定義を更新しました。
declare module '*.vue' { import type { DefineComponent } from 'vue' const component: DefineComponent<{}, {}, any> export default component }
createAppを使ってVueインスタンスを作成
以下のような形でnew VueではなくcreateApp
を使ったVueインスタンスの生成方法に変更しました。
// before import Vue from "vue"; import IndexBoardContainer from "@js/components/containers/IndexBoardContainer.vue"; new Vue({ el: "#vue-root", components: { IndexBoardContainer }, }); // After import { createApp } from "vue"; import IndexBoardContainer from "@js/components/containers/IndexBoardContainer.vue"; const app = createApp(IndexBoardContainer); app.mount("#vue-root");
Componentの書き換え
基本的には記事通りで以下のようにコンポーネントを書き換えていきます。
<script lang="ts"> import { defineComponent } from 'vue'; export default defineComponent({}) </script>
Composion APIに書き換えなくてもOptionsAPIの場合でも以下のように書き換えることで使用出来るようになりました。
// before import Vue from "vue"; export default Vue.extend({}) // after import { defineComponent } from "vue"; export default defineComponent({})
関連ライブラリまわりの対応
Webpack関係
vue-loader
requireの処理を以下のように修正しました。
const { VueLoaderPlugin } = require("vue-loader");
設定の修正
aliasの削除
以下のaliasを削除、多分buildしたものを参照しなくても良くなっている。
alias: { vue: "vue/dist/vue.esm.js",
2021/07/18 追記 互換性を維持するには消しちゃだめだった
完全ビルドが必要な場合はaliasを削除するのではなく以下に書き換える必要あり
alias: { vue: "vue/dist/vue.esm-bundler.js",
警告You are running the esm-bundler build of Vue
の抑制
以下の警告が発生するようになったので
VM373 runtime-core.esm-bundler.js:4615 You are running the esm-bundler build of Vue. It is recommended to configure your bundler to explicitly replace feature flag globals with boolean literals to get proper tree-shaking in the final bundle. See http://link.vuejs.org/feature-flags for more details.
以下を参考にしてDefinePlugin
を使って値を設定するようにしました。
plugins: [ new webpack.DefinePlugin({ __VUE_OPTIONS_API__: true, __VUE_PROD_DEVTOOLS__: false, }),
設定値の詳細はこちら
https://github.com/vuejs/vue-next/tree/master/packages/vue#bundler-build-feature-flags
vue-fontawesome
Vue3にアップグレード後に以下の警告が出るようになりました。
VM2681 runtime-core.esm-bundler.js:150 [Vue warn]: Failed to resolve component: font-awesome-icon at <FeedCard feed=
公式ガイドにしたがって@prerelease
を使うようにしました
vue-infinite-loading
I've published an pre-alpha version vue-infinite-loading@3.0.0-alpha.0-0 base on the PR branch, as the temporary way for Vue.js 3.0 projects.
vue-infinite-loading@3.0.0-alpha.0-0
が公開されているとのことで、以下のコマンドでinstall。一旦動いてそうな感じだったので、こちらをそのまま使うことにしました。
yarn add vue-infinite-loading@3.0.0-alpha.0-0
ハマった事象と対応したこと
なぜかcreateAppにComponentを指定してもレンダリングされない。
// エラーにらなずにレンダリングが走らない。 // const app = createApp({ // components: { NewBoardContainer }, // }); // こっちだと行ける const app = createApp(NewBoardContainer); // 以下のFontAwesomeIconは適用されているのでRootComponentを空にしてるとだめっぽい? app.component("FontAwesomeIcon", FontAwesomeIcon); app.mount("#vue-root");
とりあえずentryからレンダリングするcomponentは全部RootComponentにするようにmountまわりを調整して対応しました。。。
2021/07/18 追記
「2021/07/18 追記 互換性を維持するには消しちゃだめだった」に記載した件が原因、ランタイムビルドがデフォルトで読み込まれてしまうので、完全ビルドをimportする必要があった。
参考:vue/dist/vue.esm.js って何~【とりあえず動くからいいや】からの卒業~ - Qiita
RootComponentにhtmlからpropsが渡せない。
const app = createApp(ShowFeedContainer); app.component("FontAwesomeIcon", FontAwesomeIcon); app.mount("#vue-root");
<div id="vue-root"> <!-- component側だとfeedIdがundifinedになる --> <show-feed-container :feed-id="1"> </div>
解決できなかったので、ComponentのcreatedでPropsで取得していた値をAPI経由で渡すようにして対応しました。。。
2021/07/18 追記
おそらく「2021/07/18 追記 互換性を維持するには消しちゃだめだった」に記載した件が原因、ランタイムビルドがデフォルトで読み込まれてしまうので、完全ビルドをimportする必要があった。
参考:vue/dist/vue.esm.js って何~【とりあえず動くからいいや】からの卒業~ - Qiita
TypeError: babelJest.getCacheKey is not a functionが発生してjest実行時に落ちる。
https://twitter.com/TheJaredWilcurt/status/1406812612600422400
babel-jest
とjest
のバージョンをあわせたら治りました。
"babel-jest": "^26.6.3", "jest": "^26.6.3",
TypeError: moment_1.default is not a functionが発生してjest実行時に落ちる
TypeError: moment_1.default is not a function 101 | }, 102 | lastPublishedAtText: function (): string { > 103 | return moment(this.feed.lastEntry.publishedAt).format("YYYY/MM/DD h:mm:ss"); | ^ 104 | }, 105 | lastPublishedAtFromNow: function (): string { 106 | return moment(this.feed.lastEntry.publishedAt).fromNow();
Component側でimport * as moment from "moment"
するようにしたら治りました。
https://github.com/aurelia/skeleton-navigation/issues/606#issuecomment-232802977
まとめ
Vue2からVue3は結構破壊的な変更が多そうなのと、まだ対応できていない関連ライブラリ等も多そうな印象に見えたのので、まだハマりどころが多そうな印象ですが、参考になりましたら幸いです…!