いくつかのパターンをまとめましたが、簡単な修正だけで直るケースも多いです。
ただし、基本的にはプラグイン側の修正が必要なので、ここではその修正箇所をまとめています。
目次:
- ケース1: this.$xxx() 系のプラグインで起きる問題
- ケース2: <div v-xxx>系のプラグインで起きる問題
- ケース3: コンポーネント系プラグインで起きる問題
- 補足1: Vue.jsとVue 3両方に対応させる
- 補足2: プラグインの修正ってどうやるの?
ケース1: this.$xxx() 系のプラグインで起きる問題
Vueインスタンスメソッドに機能が拡張されるタイプのプラグインで起きるのは、
プラグインのインストール時、Vueのprototypeの拡張に失敗しているという事象です。
Uncaught TypeError: Object.defineProperty called on non-object
または
Uncaught TypeError: Cannot set property '$awesomeVuePlugin' of undefine
あたりのエラーが出ていないでしょうか?
プラグインがどのように注入されるか
先にVueのプラグインのインストールについて少し説明させてください。
プラグインはVue.use()
に渡されますが、ここに渡されるオブジェクトにはinstall
というメソッドが実装されている必要があります。
install
メソッドの第一引数には、Vueオブジェクトが渡されるので、それに対しdirectiveやmixin、prototypeなどを拡張することができます。
export default {
install (Vue) {
// Vueのインスタンスメソッドとしてプラグインの機能を使えるようにする
Vue.prototype.$awesomeVuePlugin = awesomeVuePlugin
}
}
Vue 3での変化
Vue 3ではVue
オブジェクトは扱わなくなります。
初期化時は代わりにcreateApp
というAPIで、アプリインスタンスを生成します。
import Vue from 'vue'
Vue.use(プラグイン)
new Vue({ ... })
import { createApp } from 'vue'
const app = createApp(...)
app.use(プラグイン) // appインスタンスに対してuseします
そしてuse()
したときに、プラグインのinstall
メソッドに渡される引数もVue
ではなくそのアプリインスタンスになります。
このappはprototypeを持ちませんので、アサインしようとして$xxx of undefined
となってしまいます。
export default {
install (app) {
console.log(app.prototype) // -> undefined
app.prototype.$xxx = ... // -> Error
}
}
解決策: globalPropertiesを使う
Vue 3では、app.config.globalPropertiesを拡張するのがその代替となります。
export default {
install (Vue) {
Vue.prototype.$awesomeVuePlugin = awesomeVuePlugin
}
}
export default {
install (app) {
app.config.globalProperties.$awesomeVuePlugin = awesomeVuePlugin
}
}
Composition APIで使う
上記の方法は、Vue3にバージョンだけ上げてOptions APIを使い続ける場合は問題ありませんが、
Composition APIを使う場合、setup内ではthis
へアクセスできませんので、this.$awesomeVuePlugin
といったことはそもそもできません。
なので、以下のようにインポートして使うような仕組みに直す必要があります。
import { useAwesomeVuePlugin } from 'awesomeVuePlugin'
プラグイン側の修正量が多くなるかもしれません。
別の案としては、代わりにprovide
/ inject
を使う方法です。
プラグイン内でprovideする
import { provide } from 'vue'
ではなく、appインスタンスが待つprovide
を使います。
export default {
install (app) {
app.config.globalProperties.$awesomeVuePlugin = awesomeVuePlugin
app.provide('awesomeVuePlugin', awesomeVuePlugin)
}
}
import { inject } from 'vue'
setup () {
const awesomeVuePlugin = inject('awesomeVuePlugin')
}
但し、プラグインで勝手にprovideするのは親切にも、ありがた迷惑にもなりそうです。
自分でprovideさせる仕組みにする、provide名を指定できるようにする、プラグイン固有の名詞など明らかに衝突しない名前にする、といった工夫が必要だと思います。
参考までに、Vuexはprovideなし、Vue routerはrouter
という名前で勝手にprovideしてくれていました。
ケース2: <div v-xxx>系のプラグインで起きる問題
次に、ディレクティブが拡張されるタイプのプラグインです。
エラーなどもなくただ機能が動作しない、といった事象が起きていませんか?
Vue 3では、カスタムディレクティブで用いられるメソッドの名前が変わったことが原因と思われます。
解決策: 新しいメソッド名に修正する
Vue.js | Vue 3 |
---|---|
bind | beforeMount |
inserted | mounted |
- | beforeUpdate |
update | - |
componentUpdated | updated |
- | beforeUnmount |
unbind | unmounted |
Ref: https://v3.vuejs.org/guide/migration/custom-directives.html#_3-x-syntax
無くなったupdate
はupdated
を使ってください。
app.directive('xxx', {
inserted (el, binding, vnode) {
el.style.background = binding.value
}
unbind () {}
})
app.directive('xxx', {
mounted (el, binding, vnode) {
el.style.background = binding.value
}
unmounted () {}
})
ケース3: コンポーネント系プラグインで起きる問題
import Slider from 'vue-awesome-slider'
export default {
components: { Slider }
}
色々な変更が影響している可能性があります。
僕が遭遇したのはライフサイクルフックの名称変更による問題です。
destroyed
がunmounted
に変わっており、コンポーネント破棄時の処理が呼ばれない問題が起きていました。
Slider = {
created () {},
destroyed () {}
}
Slider = {
created () {},
unmounted () {}
}
補足1: Vue.jsとVue 3両方に対応させる
アプリインスタンスもVue
オブジェクトもversion
というプロパティから使われているVueのバージョンを取得可能です。
これを利用して実装を分岐しましょう。
export default {
install (app) {
console.log(app.version) // -> '3.0.0-rc.12'
const isVue3 = app.version.startsWith('3')
// インスタンスメソッドの拡張
const prototype = isVue3 ? app.config.globalProperties : app.prototype
prototype.$awesomeVuePlugin = awesomeVuePlugin
// ディレクティブの拡張
app.directive('xxx', {
[isVue3 ? 'mounted' : 'inserted'] (el, binding, vnode) {
el.style.background = binding.value
}
[isVue3 ? 'unmounted' : 'unbind'] () {}
})
}
}
補足2: プラグインの修正ってどうやるの?
本題とは逸れますが、そもそもインストールしてきたプラグインをどのように修正すればよいか。
- プラグインのGitHubリポジトリを、自分のアカウントにForkする
- 該当箇所を見つけて修正する
- 本家リポジトリに(リポジトリのルールに沿って)プルリクを出す
- 本家がアップデートされるまでは
yarn add GitHubユーザー名/awesome-vue-plugin
で自分がForkしたものをインストールする