Vue3 Preliminary Exploration (3) Global API
The global APIs of the Vue2 era are all mounted on the Vue prototype, so any modification to the global API will affect all Vue instances. This may be undesirable, and such modifications are irreversible.
Therefore, in order to cope with this situation, Vue3 will transform the global API and introduce the concept of APP. Each instance is an APP, and the global API acts on the APP.
Vue 2.x has many global APIs and configurations that can change the behavior of Vue globally. For example, to create global components, you can use an API like’Vue.component ':
1 | Vue.component('button-counter', { |
Similarly, the declaration method for using global directives is as follows:
1 | Vue.directive('focus', { |
Although this declaration is convenient, it can also cause some problems.
Technically, Vue 2 has no concept of an “app”, the app we define is just a root Vue instance created with’new Vue () '. Each root instance created from the same Vue constructor function ** shares the same global configuration **, so:
- During testing, ** global configuration can easily accidentally pollute other test cases. Users need to carefully store the original global configuration ** and restore it after each test (such as resetting’Vue.config.errorHandler ‘). Some APIs ** like’Vue.use’ and’Vue.mixin ‘don’t even have a way to restore the effect **, which makes testing involving plugins particularly tricky. In fact, vue-test-utils must implement a special API’createLocalVue’ to handle this issue:
1 | import { createLocalVue, mount } from '@vue/test-utils' |
Global configuration makes it very difficult to share the same copy of Vue between multiple “apps” on the same page, but global configuration is different.
1
2
3
4
5
6
7//This affects both root instances
Vue.mixin({
/* ... */
})
const app1 = new Vue({ el: '#app-1' })
const app2 = new Vue({ el: '#app-2' })
In order to avoid these problems, in Vue 3 we introduced…
A new global
Calling createApp returns an application instance, which is a new concept in Vue 3.
1 | import { createApp } from 'vue' |
The application instance exposes a subset of the current global API. The rule of thumb is that any API that globally changes the behavior of Vue will now be moved to the application instance. Here is a table of the current global API and its corresponding instance API:
2.x Global API | 3.x Instance API (‘app’) |
---|---|
Vue.config | app.config |
Vue.config.productionTip | removed (见下方) |
Vue.config.ignoredElements | app.config.isCustomElement (见下方) |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use (见下方) |
All other global APIs that do not change behavior globally are now named exports
Instructions for Plugin Users
Plugin developers usually use’Vue.use ‘. For example, how the official’vue-router’ plugin installs itself in the browser environment:
1 | var inBrowser = typeof window ! 'undefined' |
Since the use global API is no longer in use in Vue 3, this method will stop working and calls to Vue.use () will now trigger a warning, so developers must explicitly specify the use of this plugin on the application instance.
1 | const app = createApp(MyApp) |
Mount
After initializing with createApp (/* options */), the app instance app can be used to mount with app.mount (domTarget):
1 | import { createApp } from 'vue' |
With all these changes, the components and directives at the beginning of our guide will be rewritten as follows:
1 | const app = createApp(MyApp) |
Share configuration between apps
One way to share configuration (such as components or instructions) between applications is to create factory functions as follows:
1 | import { createApp } from 'vue' |
The’focus’ directive is now available for both Foo and Bar instances and their descendants.
Webpack
In Vue 3, both global and internal APIs have been refactored with tree-shaking support in mind. As a result, global APIs are now only accessible as named exports built by ES modules. For example, our previous snippet should now look like this:
1 | import { nextTick } from 'vue' |
1 | import { shallowMount } from '@vue/test-utils' |
Calling Vue.nextTick () directly causes the infamous undefined is not a function error.
With this change, if the module binder supports tree-shaking, unused global APIs in Vue applications will be eliminated from the final bundle, resulting in optimal file sizes.