# グローバル API
breaking

Vue 2.x では、グローバルに Vue の振る舞いを変更するグローバル API や設定が多数ありました。例えば、グローバルコンポーネントを作る際には、 以下のような Vue.component API を使用していました:

Vue.component('button-counter', {
  data: () => ({
    count: 0
  }),
  template: '<button @click="count++">Clicked {{ count }} times.</button>'
})
1
2
3
4
5
6

同様に、以下のようにグローバルなディレクティブを宣言できました:

Vue.directive('focus', {
  inserted: el => el.focus()
})
1
2
3

この方法は便利でしたが、いくつか問題がありました。Vue 2 では、内部的には "app" (アプリケーション) の概念がありませんでした。私達が アプリケーションとして定義していたものは、単に new Vue() で生成された ルート Vue インスタンス でした。同じ Vue コンストラクタから作成された root インスタンスは、同じグローバル設定を共有します。その結果として:

  • グローバル設定を使用することで、テスト中に他のテストケースを誤って汚染しやすくなってしまいました。ユーザーは元のグローバル設定を保存し、各テスト後に元に戻すことを注意深くやる必要がありました (例 Vue.config.errorHandler のリセット)。Vue.use や、Vue.mixin のような API は、影響を元に戻す方法もありません。このため、プラグインを含むテストは特に厄介でした。実際、vue-test-utils はそれらに対応するために createLocalVue という特別な API を作らなければなりませんでした:
import { createLocalVue, mount } from '@vue/test-utils'

// 拡張した `Vue` コンストラクタを作成
const localVue = createLocalVue()

// "ローカル" Vue コンストラクタに、"グローバル" にプラグインをインストール
localVue.use(MyPlugin)

// `localVue` をマウントオプションに渡す
mount(Component, { localVue })
1
2
3
4
5
6
7
8
9
10
  • また、グローバル設定では、同じページ上の複数のアプリケーション間でグローバル設定が異なる Vue のコピーを共有することが困難でした。

    // 以下は両方のルートインスタンスに影響を及ぼします
    Vue.mixin({
      /* ... */
    })
    
    const app1 = new Vue({ el: '#app-1' })
    const app2 = new Vue({ el: '#app-2' })
    
    1
    2
    3
    4
    5
    6
    7

これらの問題を回避するために、Vue 3 では、以下のような API を導入しました。

# 新しいグローバル API: createApp

createApp の呼び出しでは、 Vue 3 の新しい概念である アプリケーションインスタンス を返します。

import { createApp } from 'vue'

const app = createApp({})
1
2
3

アプリケーションインスタンスは、現在のグローバル API のサブセットを公開します。おおまかには、Vue の振る舞いをグローバルに変更する全ての API は、アプリケーションインスタンスに移されます 。こちらは、現在のグローバル API とインスタンス API との対応表です:

2.x グローバル API 3.x インスタンス API (app)
Vue.config app.config
Vue.config.productionTip 削除 (以下を参照)
Vue.config.ignoredElements app.config.isCustomElement (以下を参照)
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use (以下を参照)

グローバルに振る舞いを変更しないその他のグローバル API は グローバル API の Treeshaking にあるように、名前付きエクスポートになりました。

# config.productionTip の削除

Vue 3.x では "use production build" のヒントは、"dev + full build" (ランタイムコンパイラを含み、警告があるビルド) を使用しているときにのみ表示されます。

ES Modules ビルドでは、モジュールバンドラーと一緒に使用されていることと、ほとんどの場合 CLI やボイラープレートで本番環境が適切に設定されているため、このヒントは表示されなくなりました。

# config.ignoredElementsconfig.isCustomElement に変更

この設定オプションはネイティブのカスタム要素をサポートする意図で導入されたため、それがわかるように名前に変更しました。新しいオプションでは、以前の 文字列 / RegExp の方法より、柔軟な方法を提供する関数を期待します。

// before
Vue.config.ignoredElements = ['my-el', /^ion-/]

// after
const app = Vue.createApp({})
app.config.isCustomElement = tag => tag.startsWith('ion-')
1
2
3
4
5
6

重要

Vue 3.0 では、要素がコンポーネントであるかどうかのチェックはコンパイルフェーズに移されたため、この設定はランタイムコンパイラを使用しているときにのみ尊重されます。ランタイム限定のビルドを使用している場合は、代わりにビルド設定で isCustomElement@vue/compiler-dom に渡す必要があります - 例えば compilerOptions option in vue-loader (opens new window) で。

  • ランタイム限定ビルド使用時に、config.isCustomElement が代入された場合、ビルドの設定でこのオプションを設定するように警告が表示されます。
  • これは、Vue CLI 設定の新しいトップレベルのオプションになります。

# プラグイン作者へのノート

プラグイン作者の一般的なプラクティスとして、Vue.use を使ってプラグインを自動的に UMD ビルドにインストールさせるものがありました。例えば、公式の vue-router プラグインのブラウザ環境へのインストールは以下のようになっていました:

var inBrowser = typeof window !== 'undefined'
/* … */
if (inBrowser && window.Vue) {
  window.Vue.use(VueRouter)
}
1
2
3
4
5

use グローバル API は、Vue 3 では利用できなくなったので、このメソッドは動作しなくなり、 Vue.use() の呼び出しは警告が出るようになりました。その代わりに、エンドユーザーはアプリケーションのインスタンスでプラグインを使用することを明示的に指定する必要があります。

const app = createApp(MyApp)
app.use(VueRouter)
1
2

# アプリケーションインスタンスのマウント

createApp(/* オプション */) で初期化した後、アプリケーションインスタンス app は、app.mount(domTarget) を使って Vue ルートインスタンスをマウントできます。

import { createApp } from 'vue'
import MyApp from './MyApp.vue'

const app = createApp(MyApp)
app.mount('#app')
1
2
3
4
5

これらの変更によって、このガイドの初めにあるコンポーネントとディレクティブの例は以下のように書き換えられます:

const app = createApp(MyApp)

app.component('button-counter', {
  data: () => ({
    count: 0
  }),
  template: '<button @click="count++">Clicked {{ count }} times.</button>'
})

app.directive('focus', {
  mounted: el => el.focus()
})

// このようにして、app.mount() でマウントされた全てのアプリケーションインスタンスは、
// グローバル環境を汚染すること無く、同じ "button-counter" コンポーネントと
// "focus" ディレクティブを持つようになりました。
app.mount('#app')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# Provide / Inject

Vue 2.x のルートインスタンスで provide オプションを使用するのとどうように、Vue 3 のアプリケーションインスタンスでも、アプリケーション内の任意のコンポーネントに注入できる依存関係を提供できます:

// エントリー
app.provide('guide', 'Vue 3 Guide')

// 子コンポーネント
export default {
  inject: {
    book: {
      from: 'guide'
    }
  },
  template: `<div>{{ book }}</div>`
}
1
2
3
4
5
6
7
8
9
10
11
12

# アプリケーション間での設定の共有

コンポーネントや、ディレクティブの設定をアプリケーション間で共有する方法の一つとして、以下のようなファクトリ関数があります:

import { createApp } from 'vue'
import Foo from './Foo.vue'
import Bar from './Bar.vue'

const createMyApp = options => {
  const app = createApp(options)
  app.directive('focus' /* ... */)

  return app
}

createMyApp(Foo).mount('#foo')
createMyApp(Bar).mount('#bar')
1
2
3
4
5
6
7
8
9
10
11
12
13

このようにして、 fucus ディレクティブは Foo と Bar 両方のインスタンスとその子で有効になります。

Deployed on Netlify.
最終更新日: 11/3/2020, 10:51:11 PM