reference resources:
Interviewer: Vue instance mounting process
The difference between runtime compiler and runtime only in vue
Explanation of different builds
If there are any errors, please point them out~
For more study notes, please stamp: https://github.com/6fa/WebKno...
Contents of this document:
1. Source code core directory
2. Source code construction
3. Runtime only and runtime compiler
4. Entry (runtime+compiler mode)
1. Source code core directory
For the Vue2 source code, you can view the official github: https://github.com/vuejs/vue
The source code is mainly placed in the src Directory:
src ├── compiler # Compile related ├── core # Core code ├── platforms # Support of different platforms ├── server # Server side rendering ├── sfc # . vue file parsing ├── shared # Shared tool code
compiler
- Store compilation related code, including
- Parse the template into ast tree (abstract syntax tree), AST tree optimization and code generation
core
- Core code, including
- Built in components, global API encapsulation, tool functions
- Vue instantiation, responsive, virtual DOM
platforms
- vue.js entry
- The two directories represent two main entries, which are packaged into vue.com running on the web and weex respectively js
server
- Server side rendering related
sfc
- Handle The vue file is parsed into a js object
shared
- Some tools will be used by browser Vue JS and server Vue JS sharing
2. Source code construction
In the package of the source code As you can see from the JSON file, the entry to build the code is scripts / build js:
{ //... "scripts": { //... "build": "node scripts/build.js", "build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer", "build:weex": "npm run build -- weex", //... } }
scripts/build.js key code:
- First read the configuration from the configuration file (config), and then filter the build configurations (builds) through the command-line parameters to build Vue. Net for different purposes js
- build() is built by rollup (packaging tool)
//scripts/build.js let builds = require('./config').getAllBuilds() // filter builds via command line arg // Filter builds by comparing command line parameters if (process.argv[2]) { const filters = process.argv[2].split(',') builds = builds.filter(b => { return filters.some(f => b.output.file.indexOf(f) > -1 || b._name.indexOf(f) > -1) }) } else { // filter out weex builds by default // weex builds are filtered out by default builds = builds.filter(b => { return b.output.file.indexOf('weex') === -1 }) } build(builds)
Take another look at the config configuration file:
// script/config.js //Configuration follows Rollup's build rules const builds = { // Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify 'web-runtime-cjs': { entry: resolve('web/entry-runtime.js'), //Build entry dest: resolve('dist/vue.runtime.common.js'), //Built file location format: 'cjs', //Construction format, cjs means to follow CommonJS, ES means ES Module, and UMD means UMD specification banner }, // Runtime+compiler CommonJS build (CommonJS) 'web-full-cjs': { entry: resolve('web/entry-runtime-with-compiler.js'), dest: resolve('dist/vue.common.js'), format: 'cjs', alias: { he: './entity-decoder' }, banner }, //... }
3. Runtime only and runtime compiler
compiler:
Code used to compile template strings into JavaScript rendering functions
runtime:
Code used to create Vue instances, render and process virtual DOM, etc. It's basically removing everything else from the compiler
runtime + compiler (full version):
If you write a template, you need to compile the template into a render function (generate a virtual DOM) at run time. Because in Vue2, the final rendering is through the render function. If you write the template attribute, you need to compile it into the render function, and you need the compiler.
// Compiler required new Vue({ template: '<div>{{ hi }}</div>' }) // No compiler required new Vue({ render (h) { return h('div', this.hi) } })
runtime only:
You need to use the vue loader of webpack vue files are compiled into JS files: templates inside vue files are precompiled into JavaScript at build time. (at this time, the new Vue option in main.js still cannot write the template attribute, only the. vue file can be written.)
Since the compiler is no longer required, the volume is reduced by about 30%, and the runtime only version should be used as much as possible.
4. Entry (runtime+compiler mode)
runtime+compiler mode entry file location: Src / platforms / Web / entry runtime with compiler js
The code focuses on:
- Vue is introduced (the entry of Vue is. / runtime/idex)
- The $mount method is defined on Vue's prototype
- Export Vue
import config from 'core/config' import { warn, cached } from 'core/util/index' import { mark, measure } from 'core/util/perf' import Vue from './runtime/index' import { query } from './util/index' import { compileToFunctions } from './compiler/index' import { shouldDecodeNewlines, shouldDecodeNewlinesForHref } from './util/compat' //... //Define $mount method const mount = Vue.prototype.$mount Vue.prototype.$mount = function (){......} //... Vue.compile = compileToFunctions export default Vue
4.1 Vue entrance
The location where Vue is introduced above is Src / platforms / Web / Runtime / index js
Code focus:
- Importing Vue from core/index
- Some extensions are made to Vue objects, such as defining the basic $mount method on the Vue prototype
From core / index JS can see again
- Vue objects are imported from core/instance/index, so the real Vue instance is defined in core/instance/index
- Initialize global API: initGlobalAPI(Vue)
// src/platforms/web/runtime/index.js import Vue from 'core/index' import config from 'core/config' import { extend, noop } from 'shared/util' import { mountComponent } from 'core/instance/lifecycle' import { devtools, inBrowser } from 'core/util/index' import { query, //...... } from 'web/util/index' //...... // install platform specific utils Vue.config.mustUseProp = mustUseProp //...... // public mount method Vue.prototype.$mount = function ( el?: string | Element, hydrating?: boolean ): Component { el = el && inBrowser ? query(el) : undefined return mountComponent(this, el, hydrating) } //...... export default Vue
// core/index import Vue from './instance/index' import { initGlobalAPI } from './global-api/index' import { isServerRendering } from 'core/util/env' import { FunctionalRenderContext } from 'core/vdom/create-functional-component' initGlobalAPI(Vue) //...... export default Vue
4.1.1 definition of Vue
Location: core/instance/index, key points:
- Vue constructor is defined (why not use class? Vue is passed as a parameter later, mainly to the prototype expansion methods of Vue. These expansion methods are scattered in various modules, and it is difficult to implement if it is class)
- Xxxmixin expands some methods on Vue's prototype, such as_ The init method is added in initMixin
import { initMixin } from './init' import { stateMixin } from './state' import { renderMixin } from './render' import { eventsMixin } from './events' import { lifecycleMixin } from './lifecycle' import { warn } from '../util/index' function Vue (options) { if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue) ) { warn('Vue is a constructor and should be called with the `new` keyword') } this._init(options) } initMixin(Vue) stateMixin(Vue) eventsMixin(Vue) lifecycleMixin(Vue) renderMixin(Vue) export default Vue
4.1.2 initGlobalAPI
The above is for Vue If the prototype extends the method, the initglobal API adds static methods to Vue itself.
Location: Src / core / global API / index js
//...... export function initGlobalAPI (Vue: GlobalAPI) { // config const configDef = {} configDef.get = () => config if (process.env.NODE_ENV !== 'production') { configDef.set = () => { warn( 'Do not replace the Vue.config object, set individual fields instead.' ) } } Object.defineProperty(Vue, 'config', configDef) // Vue. It is better not to rely on the method of util exposure, because it may change frequently and is unstable Vue.util = { warn, extend, mergeOptions, defineReactive } Vue.set = set Vue.delete = del Vue.nextTick = nextTick // 2.6 explicit observable API Vue.observable = <T>(obj: T): T => { observe(obj) return obj } Vue.options = Object.create(null) ASSET_TYPES.forEach(type => { Vue.options[type + 's'] = Object.create(null) }) // this is used to identify the "base" constructor to extend all plain-object // components with in Weex's multi-instance scenarios. Vue.options._base = Vue extend(Vue.options.components, builtInComponents) initUse(Vue) initMixin(Vue) initExtend(Vue) initAssetRegisters(Vue) }
4.2 mount
$mount method focus:
- If template or el is defined, the innerHTML of template or el is converted to the render function
- The transformation is implemented through compileToFunctions
- Finally, the shared $mount method is mounted on the Vue prototype. This is done in order to reuse. The runtime mode is used directly, and it saves the steps to convert render functions. The location is in src/platform/web/runtime/index.js.
- The $mount method actually calls the mountComponent method (defined in src/core/instance/lifecycle.js)
const mount = Vue.prototype.$mount Vue.prototype.$mount = function ( el?: string | Element, hydrating?: boolean ): Component { el = el && query(el) //... const options = this.$options // Convert the outerHTML of template or el to the render function if (!options.render) { let template = options.template if (template) { if (typeof template === 'string') { //template is a string if (template.charAt(0) === '#') { template = idToTemplate(template) //idToTemplate is the innerHTML of the element obtained by id //... } } else if (template.nodeType) { //template is a node template = template.innerHTML } else { //Invalid template if (process.env.NODE_ENV !== 'production') { warn('invalid template option:' + template, this) } return this } } else if (el) { //If template does not exist but el exists template = getOuterHTML(el) } if (template) { //... // compileToFunctions converts template to render function const { render, staticRenderFns } = compileToFunctions(template, { //... Options passed }, this) options.render = render options.staticRenderFns = staticRenderFns //... } } return mount.call(this, el, hydrating) }
// src/platform/web/runtime/index.js // Reusable share $mount Vue.prototype.$mount = function ( el?: string | Element, hydrating?: boolean ): Component { el = el && inBrowser ? query(el) : undefined return mountComponent(this, el, hydrating) }
4.3 summary
runtime+compiler mode entry (SRC / platforms / Web / entry runtime with compiler. JS)
Introduce vue from runtime/index (src/platforms/web/runtime/index.js)
Importing Vue from core/index
Vue objects are imported from core/instance/index, so the real Vue instance is defined in core/instance/index
- Vue constructor defined
- Some methods to expand Vue's prototype
- Initialize global API: initGlobalAPI(Vue)
- Expand Vue objects, such as defining the basic $mount method on Vue prototype
Define $mount on the vue prototype (note that the shared $mount method is different)
- Convert template to render function, which is implemented through compileToFunctions
- Call the base $mount method (src/platform/web/runtime/index.js)
- The base $mount method actually calls the mountComponent method (src/core/instance/lifecycle.js)