Introduction: This paper is based on Vue 3.0.5 for analysis, mainly for personal learning comb process. It was also the first time I had written a serious article. Correct me if I am wrong.
What does createAppAPI do
The preface raises a question:
- whyVue3To pass the
createApp({setup(){}}).mount('#app')
This method is implemented functionally, not in the same wayVue2throughnew Vue()
The way?
Don’t say much about the source code
createAppAPI
export function createAppAPI<HostElement> (render: RootRenderFunction, hydrate? : RootHydrateFunction) :CreateAppFunction<HostElement> {
return function createApp(rootComponent, rootProps = null) {
// omit createApp internal code}}Copy the code
CreateAppAPI is just a wrapper around the implementation of createApp. Moving on to see what the main implementation of the createApp method does.
createApp
// Omit some DEV environment code
return function createApp(rootComponent, rootProps = null) {
// The main use of the up-down factory function is to initialize some data. See below
const context = createAppContext()
const installedPlugins = new Set(a)// mark the mount status
let isMounted = false
const app: App = (context.app = {
_uid: uid++,
_component: rootComponent as ConcreteComponent,
_props: rootProps,
_container: null._context: context,
version,
// Omit some code
// Plug-in installation
use(plugin: Plugin, ... options: any[]) {
Vue2 vue.use (vueRouter) * vue3 app. Use (vueRouter) * 1. Global configuration contaminates * 2. Treeshaking optimization * 3. Semantic * /
// installedPlugins are set key unique
if(plugin && isFunction(plugin.install)) { installedPlugins.add(plugin) plugin.install(app, ... options) }else if(isFunction(plugin)) { installedPlugins.add(plugin) plugin(app, ... options) }return app
},
// global mixin
mixin(mixin: ComponentOptions) {
// Core logic
if(! context.mixins.includes(mixin)) { context.mixins.push(mixin)/ / judge whether the components of the mixed with existing props | emits attribute, if there is not data merging processing (subsequent)
if (mixin.props || mixin.emits) {
context.deopt = true}}return app
},
// Global component mountcomponent(name: string, component? : Component): any {// No component creation method passed in returns the bound value of undefined or the registered creation method
if(! component) {return context.components[name]
}
// Mount to the component object
context.components[name] = component
return app
},
// Global custom instruction mount
directive(name: string, directive? : Directive) {
// The logic is similar to component mounting
if(! directive) {return context.directives[name] as any
}
context.directives[name] = directive
return app
},
/** * TODO mount phase focus *@param {HostElement} RootContainer Mount element node *@param {boolean} [isHydrate]
* @return {*} {*}* /mount(rootContainer: HostElement, isHydrate? : boolean): any {// Check the isMounted mounting status
if(! isMounted) {//TODO gets the vNode of the entire tree when mounted
// createApp(base).mount('#app')
// Virtual DOM creation method
const vnode = createVNode(
rootComponent as ConcreteComponent,
rootProps
)
// Store the initialization up and down on the appContext property of the root node
vnode.appContext = context
if (isHydrate && hydrate) {
hydrate(vnode as VNode<Node, Element>, rootContainer as any)
} else {
// The vNode passed in by the TODO renderer generates a node to mount to the root node
render(vnode, rootContainer)
}
// Modify tag is mounted
isMounted = true
// Bind the root node element
app._container = rootContainer
// for devtools and telemetry; (rootContaineras any).__vue_app__ = app
// Return an instance of Vue
returnvnode.component! .proxy } },/ / unloading
unmount() {
// The first argument to the render function is vnode, which checks that if there is no vnode and _vnode exists on the root instance, unmount it
if (isMounted) {
render(null, app._container)
}
},
// global provide
provide(key, value) {
/* * Sets a value that can be injected into all application-wide components. Components should use Inject to receive supplied values. * Note * provide and Inject binding are not reactive. This is intentional. * However, if you pass down a responsive object, the property on that object will remain responsive. * /
context.provides[key as string] = value
return app
}
})
return app
}
Copy the code
Vue context creates createAppContext
export function createAppContext() :AppContext {
return {
app: null as any,
config: {
// const NO = () => false
isNativeTag: NO,
performance: false.globalProperties: {},
optionMergeStrategies: {},
isCustomElement: NO,
errorHandler: undefined.warnHandler: undefined
},
mixins: [].components: {},
directives: {},
provides: Object.create(null)}}Copy the code
conclusion
In createAppAPI we found that its main function is to create an instance of Vue. And bind global data and context to the current Vue instance. The element is eventually mounted by calling the mount method
Follow-up articles:
Vue3 parse series of mount functions
Data responsivity of Vue3 parse series
This is the first article of Vue3 parsing. The Vue3 mount phase will be analyzed later.