In this article, we will first look at how the application initialization code in the Vue 2 application works. Then we will see what its shortcomings are, and how to eliminate these shortcomings through the new initialization syntax used in version 3 of the Vue framework.
Let's talk about the current initialization method in Vue 2. Usually, in the src/main.js
file, we guide the application by calling a new Vue as a constructor for creating an application instance.
import Vue from "vue";
import App from "./App.vue";
import router from './router'
import SomeComponent from '@/components/SomeComponent.vue'
import SomePlugin from '@/plugins/SomePlugin'
const vue2AppCopy = new Vue({
router,
render: h => h(App)
});
vue2AppCopy.component('SomeComponent',SomeComponent);
vue2AppCopy.use(SomePlugin);
vue2AppCopy.$mount('#app')
This application example will serve all logic throughout the life cycle of our SPA. All this is fine, we have been using this syntax to guide our Vue applications for about 3 years.
However, in Vue 3, the initialization code syntax has changed. Let us first look at the new syntax, and then look at the benefits of using it.
New Vue 3 createApp method
In Vue 3, we have a special createApp
to achieve this. The createApp function takes a root component ( App.vue
) as a parameter and returns a Vue application instance. Therefore, the simplest application initialization is as follows:
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
The Vue application instance returned by createApp is also called the application context object. This object can be used to further add more functions to the application during the boot process. Here is an example of a more advanced initialization code:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import SomeComponent from '@/components/SomeComponent.vue'
import SomePlugin from '@/plugins/SomePlugin'
const myV3App = createApp(App)
myV3App.component('SomeComponent', SomeComponent)
myV3App
.use(SomePlugin)
.use(router)
// add more functionality to myV3App
// now we're ready to mount
myV3App.mount('#app')
Compared with V2, there is not much change in adding additional logic (such as plug-ins and components), right?
You can find a complete overview of the supported methods Vue 3 document
This is great, but there is a small but important change-we used a special function instead of the new Vue
instance.
//v2
const vue2App = new Vue({}) // Working with the main Vue instace
//v3
const myV3App = createApp(App).mount('#app') // Create a copy of the Vue instance
So why is it better to use the new dedicated createApp
function than the new Vue
constructor?
Benefits of Vue 3 initialization code
In the Vue 2 application initialization code, we used the Vue object imported from the library to create this application instance and all other new application instances.
Using this method, it is impossible to isolate some functions into only one Vue instance, because the Vue application still uses the same Vue object imported from the library.
To demonstrate this, let's take a look at the following example-as you can see, both vue2AppOne
and vue2AppTwo
can access an instruction myDirective
Vue.directive('myDirective', {
/* ... */
})
Vue.component({
/* ... */
})
const vue2AppOne = new Vue(/**/).mount('#app1')
const vue2AppTwo = new Vue(/**/).mount('#app1')
It may not be common to create multiple Vue applications in one website or application.
But with the expansion of the project scale, development by different teams, and the popularity of front-end microservices, you may find yourself doing the same at some point.
Then, it is almost impossible to use v2 syntax to obtain another Vue instance with a different function.
The new syntax in Vue 3 allows us to treat the configuration of each application as a separate custom object, because the application uses a dedicated function ( createApp
) to create an independent instance.
The new architecture allows us to have two or more isolated Vue instances, which by default do not share any features, even if they are created in one file.
However, if you want to share some functions between the two instances, you can! In the example below, vue3AppOne
and vue3AppTwo
share LocalePlugin
, but not searchchinputcomponent
.
const config = {/* some global config */}
const vue3AppOne = Vue.createApp(config)
vue3AppOne.component('SearchInput', SearchInputComponent)
vue3AppOne.use(LocalePlugin)
const vue3AppTwo = Vue.createApp(config)
vue3AppTwo.use(LocalePlugin)
To demonstrate this behavior, we created a code repository with 2 simple Vue 3 instances. Because of the new createApp
syntax, these instances do not share components and instructions. Please take a look at how it is played locally.
In the matching warehouse, we initialized two Vue 3 applications in two different containers of a page template, see public/index.html .
<div id="header-app"></div>
<div id="main-app"></div>
One application will be marked as a relatively simple header, while the other will be able to use the router and cooperate with the store.
Using Vue 3 syntax, we can easily separate them in the initialization code of the src/main.js file:
import { createApp } from 'vue'
import App from './App.vue'
import Header from './Header.vue'
import router from './router'
import store from './store'
createApp(App)
.use(store)
.use(router)
.mount('#main-app')
createApp(Header)
.mount('#header-app')
If you vue serve
, you should be able to see the two parts working on one page. In the console output, you will see that the Main application can use Vuex
access vue-router
and the store, but the Header application cannot.
created () {
console.log('Hello from Main app')
console.log('Main app router', this.$route)
console.log('Main app store:', this.$store)
}
A more direct test setup
If you are using vue-test-utils
(version <2.0.0) to write tests for your Vue 2 components, you may encounter createLocalVue
method to avoid polluting the global Vue instance.
There are the same potential problems in our test scenario as in the Vue 2 application. When we add components, plugins, etc., it will pollute the global Vue instance, and they are all shared with every available Vue instance.
To solve this problem, we must use createlocalvalue
, which (you guessed it) creates a new isolated local Vue instance.
import { createLocalVue, mount } from '@vue/test-utils'
import MyPlugin from '@/plugins/MyPlugin'
const localVueForTest = createLocalVue()
localVueForTest.use(MyPlugin)
mount(Component, {
localVueForTest
})
This is no longer a problem in Vue 3, because all application extensions: plugins, mixins and global components will not change the global Vue instance. vue-test-utils
(version >= 2.0.0) is used in Vue 3, the application initialization code in the test file will look like this:
import { createStore } from 'vuex'
import { mount } from '@vue/test-utils'
import App from '@/App'
import MyPlugin from '@/plugins/MyPlugin'
const wrapper = mount(App, {
global: {
plugins: [MyPlugin]
}
})
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。