createApp

Returns an application instance that provides the application context. The entire tree of components mounted by the application instance shares the same context.

import { createApp } from 'vue'

const app = createApp({})
Copy the code

You can chain-call other methods after createApp, which can be found in the application API.

parameter

This function takes two arguments, the first being the root component option object and the second passing the root prop to the application

Start with a chestnut

const { createApp } = Vue;

createApp({
    data() {
        return {
            title: 'hello, Vue3~'
        }
    }
}).mount('#demo');
Copy the code

So let’s see what happens in the createApp method, okay?

// packages/runtime-dom/src/index.ts
export const createApp = ((. args) = > {
  constapp = ensureRenderer().createApp(... args)if (__DEV__) {
    injectNativeTagCheck(app)
    injectCompilerOptionsCheck(app)
  }

  const { mount } = app
  app.mount = (containerOrSelector: Element | ShadowRoot | string): any= > {
    const container = normalizeContainer(containerOrSelector)
    if(! container)return

    const component = app._component
    if(! isFunction(component) && ! component.render && ! component.template) {// __UNSAFE__
      // Reason: potential execution of JS expressions in in-DOM template.
      // The user must make sure the in-DOM template is trusted. If it's
      // rendered by the server, the template should not contain any user data.
      component.template = container.innerHTML
      // 2.x compat check
      if (__COMPAT__ && __DEV__) {
        for (let i = 0; i < container.attributes.length; i++) {
          const attr = container.attributes[i]
          if(attr.name ! = ='v-cloak' && /^(v-|:|@)/.test(attr.name)) {
            compatUtils.warnDeprecation(
              DeprecationTypes.GLOBAL_MOUNT_CONTAINER,
              null
            )
            break}}}}// clear content before mounting
    container.innerHTML = ' '
    const proxy = mount(container, false, container instanceof SVGElement)
    if (container instanceof Element) {
      container.removeAttribute('v-cloak')
      container.setAttribute('data-v-app'.' ')}return proxy
  }

  return app
}) as CreateAppFunction<Element>
Copy the code

The emphasis in the createApp method is one that is ensureRenderer

// packages/runtime-dom/src/index.ts
const rendererOptions = extend({ patchProp, forcePatchProp }, nodeOps)

// lazy create the renderer - this makes core renderer logic tree-shakable
// in case the user only imports reactivity utilities from Vue.
let renderer: Renderer<Element> | HydrationRenderer

let enabledHydration = false

function ensureRenderer() {
  return renderer || (renderer = createRenderer<Node, Element>(rendererOptions))
}
Copy the code

CreateRenderer is called in the ensureRenderer method

// packages/runtime-core/src/renderer.ts
export function createRenderer<
  HostNode = RendererNode.HostElement = RendererElement> (options: RendererOptions<HostNode, HostElement>) {
  return baseCreateRenderer<HostNode, HostElement>(options)
}
Copy the code

BaseCreateRenderer is called in the createRenderer method. Vnode, DIff and patch are completed in the baseCreateRenderer method, which is relatively large. The three parameters “render”, “hydrate”, and “createApp” are returned, which is the createApp() call to the createApp method with” ensureRenderer “().

// packages/runtime-core/src/renderer.ts
// overload 1: no hydration
function baseCreateRenderer<
  HostNode = RendererNode.HostElement = RendererElement> (options: RendererOptions<HostNode, HostElement>) :Renderer<HostElement>

// overload 2: with hydration
function baseCreateRenderer(
  options: RendererOptions<Node, Element>,
  createHydrationFns: typeof createHydrationFunctions
) :HydrationRenderer

// implementation
function baseCreateRenderer(options: RendererOptions, createHydrationFns? :typeof createHydrationFunctions
) :any {// omit 2000 linesreturn {
        render.hydrate.createApp: createAppAPI(render, hydrate)}}Copy the code

The createApp method returned calls createAppAPI and passes in the generated Render and hydrate parameters. CreateApp first evaluates the rootProps with familiar methods in the app object, consistent with existing API calls

// packages/runtime-core/src/apiCreateApp.ts
export function createAppAPI<HostElement> (render: RootRenderFunction, hydrate? : RootHydrateFunction) :CreateAppFunction<HostElement> {
  return function createApp(rootComponent, rootProps = null) {
    if(rootProps ! =null && !isObject(rootProps)) {
      __DEV__ && warn(`root props passed to app.mount() must be an object.`)
      rootProps = null
    }

    const context = createAppContext()
    const installedPlugins = new Set(a)let isMounted = false

    const app: App = (context.app = {
      _uid: uid++,
      _component: rootComponent as ConcreteComponent,
      _props: rootProps,
      _container: null._context: context,

      version,

      get config() {
        return context.config
      },

      set config(v) {
        if (__DEV__) {
          warn(
            `app.config cannot be replaced. Modify individual options instead.`)}},use() {},

      mixin() {},

      component() {},

      directive() {},

      mount() {},

      unmount() {},

      provide(){}})if (__COMPAT__) {
      installAppCompatProperties(app, context, render)
    }

    return app
  }
}
Copy the code

The realization of the createAppContext

// packages/runtime-core/src/apiCreateApp.ts
export function createAppContext() :AppContext {
  return {
    app: null as any,
    config: {
      isNativeTag: NO,
      performance: false.globalProperties: {},
      optionMergeStrategies: {},
      errorHandler: undefined.warnHandler: undefined.compilerOptions: {}},mixins: [].components: {},
    directives: {},
    provides: Object.create(null)}}Copy the code

CreateAppAPI returns the app instance object and the createApp process is complete