1
头图

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]
  }
})

杭州程序员张张
11.8k 声望6.7k 粉丝

Web/Flutter/独立开发者/铲屎官