Vue Implementation 03

Now, we made clear about the constructor of Vue, which is core/instance/index.js and core/index.js. The former one is the definition of the constructor of Vue. The latter one is to define global APIs, which is static functions and properties to Vue. These two files have something in common: They are both located in core. We has descriped the directory when we introducing Vue. Files stored in core is platform-unrelated code. Therefore, core/instance/index.js and core/index.js are both decorating core Vue parts and they are both platform-unrelated.

However, Vue is a multi-platform project, and it can be ported into Web and Weex. Different platform has different components, directives and some platform-related functions. Thereform, Vue has to be packaged targeting to different platforms. So what we are going to take a look at is platforms/web/runtime/index.js, which is our path to find Vue's construtor.

Before we are taking dive into this file, we can open platforms folder and we can see there are two sub-directories, which is web and weex. These folders is to pack Vue targeting to different platform. As for our concerning web platform, it is included here as well.

Then, we open platform/web/runtime/index.js and look at it. There are a lot import at the beginning of this file, including importing Vue from core/index.js.

Below import, there is a piece of code:

// install platform specific utils
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag
Vue.config.isReservedAttr = isReservedAttr
Vue.config.getTagNamespace = getTagNamespace
Vue.config.isUnknownElement = isUnknownElement

Do you remember Vue.config? What it proxying is the object exported by core/config.js. It first looks like this:

Vue.config = {
  optionMergeStrategies: Object.create(null),
  silent: false,
  productionTip: process.env.NODE_ENV !== 'production',
  devtools: process.env.NODE_ENV !== 'production',
  performance: false,
  errorHandler: null,
  warnHandler: null,
  ignoredElements: [],
  keyCodes: Object.create(null),
  isReservedTag: no,
  isReservedAttr: no,
  isUnknownElement: no,
  getTagNamespace: noop,
  parsePlatformTagName: identity,
  mustUseProp: no,
  _lifecycleHooks: LIFECYCLE_HOOKS
}

We can see, properties of the config object exported by core/config.js, are mostly defined as a initial value. And we can see many comments in core/config.js as below:

/**
 * Check if a tag is reserved so that it cannot be registered as a 
 * component. This is platform-dependent and may be overritten.
 */
isReservedTag: no,

/**
 * Check if an attribute is reserved so that it cannot be used as a component
 * prop. This is platform-dependent and may be overritten.
 */
isReservedAttr: no,

This is platform-dependent and may be overritten. What it means is that this configuration is platform-dependent. And it is very likely to be overritten. Now, we can go back to this code:

// install platform specific utils
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag
Vue.config.isReservedAttr = isReservedAttr
Vue.config.getTagNamespace = getTagNamespace
Vue.config.isUnknownElement = isUnknownElement

Actually, it is overriding properties of config exported by default. It is commented that it will install platform specific utils. As for their effect, we will discuss later.

And there are two lines of code:

// install platform runtime directives & components
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)

They will install platform runtime directives and components. Do you remember how is Vue.options look like? Before these lines executed, it is something like this:

Vue.options = {
 components: {
  KeepAlive
 },
 directives: Object.create(null),
 filters: Object.create(null),
 _base: Vue
}

We have once met extend function. In case you forget that, you can always refer to the appendix for /shared/util.js. So what will it look like after these lines? We need to know what is platformDirectives and platformComponents.

According to import at the beginning:

import platformDirectives from './directives/index'
import platformComponents from './components/index'

We know that these varible is imported from runtime/directives/index.js and runtime/components/index.js. We open runtime/directives/index.js and:

import model from './model'
import show from './show'

export default {
  model,
  show
}

That is to say that platformDirectives is:

platformDirectives = {
  model,
  show
}

Therefore, after extend is executed, Vue.options become:

Vue.options = {
 components: {
  KeepAlive
 },
 directives: {
  model,
  show
 },
 filters: Object.create(null),
 _base: Vue
}

runtime/components/index.js is:

import Transition from './transition'
import TransitionGroup from './transition-group'

export default {
  Transition,
  TransitionGroup
}

So platformComponents is:

platformComponents = {
  Transition,
  TransitionGroup
}

After extend, Vue.options become:

Vue.options = {
 components: {
  KeepAlive,
  Transition,
  TransitionGroup
 },
 directives: {
  model,
  show
 },
 filters: Object.create(null),
 _base: Vue
}

So we make clear about these code. It added specific components and directives targeting web platform.

Let's get to the remaining code:

// install platform patch function
Vue.prototype.__patch__ = inBrowser ? patch : noop

// public mount method
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
  el = el && inBrowser ? query(el) : undefined
  return mountComponent(this, el, hydrating)
}

It added __patch__ to Vue.prototype. If you are running in a browser, it will be patch function. Else, it will be a empty function noop. Then, it added $mount function to Vue.prototype. We skip the $mount and its effect.

Next, it is the global hook of vue-devtools. It is wrapped in setTimeout and finally exports Vue.

So we have read platforms/web/runtime/index.js. Its effect is decorating Vue targeting different platform:

  • It sets Vue.config for platform
  • It mixed two directives: model and show
  • It mixed two components: Transition and TransitionGroup
  • It added two functions to Vue.prototype: __patch__ and $mount

After this file excuted, Vue.options, Vue.config and Vue.prototype are changed. We can refer these changes in appendix.