skip to content
天真笔录

vue入口探索

/ 3 min read

打包入口文件

扩展$mount,处理el和template

// platforms/web/entry-runtime-with-compiler.js
Vue.prototype.$mount = function () {
	const options = this.$options;
	// 如果没有render函数选项,则将template/el的设置转为render
	if (!options.render) {
		if (options.template) {
			// 解析template
		} else if (el) {
			// 否则解析el选项
			template = getOuterHTML(el);
		}
		if (template) {
			const { render, staticRenderFns } = compileToFunctions(
				template,
				{
					outputSourceRange: process.env.NODE_ENV !== "production",
					shouldDecodeNewlines,
					shouldDecodeNewlinesForHref,
					delimiters: options.delimiters,
					comments: options.comments,
				},
				this,
			);
			options.render = render;
		}
	}
};
  • 从上面代码可知

    render/template/el同时存在时,render>template>el

web运行时代码

1. 实现$mount

// platforms/web/runtime/index.js
Vue.prototype.$mount = function () {
	return mountComponent(this, el, hydrating);
};
// src/core/instance/lifecycle.js
function mountComponent() {
	callHook(vm, "beforeMount");
	// 组件的跟新函数
	updateComponent = () => {
		// vm._render()得到虚拟dom
		vm._update(vm._render(), hydrating);
	};
	// 在 Watcher实例中做组件更新 updateComponent
	// vue2中一个组件对应一个Watcher实例
	new Watcher(
		vm,
		updateComponent,
		noop,
		{
			before() {
				if (vm._isMounted && !vm._isDestroyed) {
					callHook(vm, "beforeUpdate");
				}
			},
		},
		true /* isRenderWatcher */,
	);
	if (vm.$vnode == null) {
		vm._isMounted = true;
		callHook(vm, "mounted");
	}
	return vm;
}
Watcher
// src/core/observer/watcher.js
class Watcher {
	// expOrfn: 可能是表达式,函数
	constructor(vm, expOrFn, cb) {
		this.vm = vm;
		if (typeof expOrFn === "function") {
			this.getter = expOrFn; // 上面传进来的是函数
		}

		this.get();
	}

	get() {
		pushTarget(this); // 当前watcher保存到Dep中  src/core/observer/dep.js
		const vm = this.vm;
		this.getter.call(vm, vm); // 执行刚才的updateComponent
	}

	addDep(dep) {
		const id = dep.id;
		if (!this.newDepIds.has(id)) {
			this.newDepIds.add(id);
			this.newDeps.push(dep); // watcher中添加dep
			if (!this.depIds.has(id)) {
				dep.addSub(this); // dep中添加watcher
			}
		}
	}
}

dep详情

2. Vue.prototype.patch = inBrowser ? patch : noop

patch: dom diff

core/index.js

import Vue from "./instance/index";
initGlobalAPI(Vue); // 全局API实现 ./global-api/index'

实例入口

// core/instance/index.js
function Vue() {
	this._init();
}

initMixin(Vue);
stateMixin(Vue);
eventsMixin(Vue);
lifecycleMixin(Vue);
renderMixin(Vue);

initMixin

// core/instance/init.js
function initMixin(Vue) {
	Vue.prototype._init = function () {
		// 选项合并
		vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor), options || {}, vm);

		initLifecycle(vm); // 初始化实例属性 $parent\$children\$root
		initEvents(vm); // 初始化组件自定义事件
		initRender(vm); // 插槽解析$slots, _c/$createElements
		callHook(vm, "beforeCreate");
		initInjections(vm); // resolve injections before data/props
		initState(vm); // 初始化 props、methods、data、computed、watch
		initProvide(vm); // resolve provide after data/props
		callHook(vm, "created");
	};
}