exportfunctioninitMixin(Vue: typeof Component) { Vue.prototype._init = function (options?: Record<string, any>) { constvm: Component = this // a uid vm._uid = uid++
let startTag, endTag /* istanbul ignore if */ if (__DEV__ && config.performance && mark) { startTag = `vue-perf-start:${vm._uid}` endTag = `vue-perf-end:${vm._uid}` mark(startTag) }
// a flag to mark this as a Vue instance without having to do instanceof // check vm._isVue = true // avoid instances from being observed vm.__v_skip = true // effect scope vm._scope = newEffectScope(true/* detached */) vm._scope._vm = true // merge options if (options && options._isComponent) { // optimize internal component instantiation // since dynamic options merging is pretty slow, and none of the // internal component options needs special treatment. initInternalComponent(vm, options asany) } else { vm.$options = mergeOptions( resolveConstructorOptions(vm.constructorasany), options || {}, vm ) } /* istanbul ignore else */ if (__DEV__) { initProxy(vm) } else { vm._renderProxy = vm } // expose real self vm._self = vm initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, 'beforeCreate', undefined, false/* setContext */) initInjections(vm) // resolve injections before data/props initState(vm) initProvide(vm) // resolve provide after data/props callHook(vm, 'created')
/* istanbul ignore if */ if (__DEV__ && config.performance && mark) { vm._name = formatComponentName(vm, false) mark(endTag) measure(`vue ${vm._name} init`, startTag, endTag) }
if (vm.$options.el) { vm.$mount(vm.$options.el) } } }
// inject renderer internals for keepAlive // 将默认的渲染方法,加入到 KeepAliveContext 当然的 render 当中 if (isKeepAlive(initialVNode)) { ;(instance.ctxasKeepAliveContext).renderer = internals }
// resolve props and slots for setup context // 其实不仅仅是解析,还执行了 setup函数 setupComponent(instance)
// setup() is async. This component relies on async logic to be resolved // before proceeding // 处理异步逻辑的情况,需要等待 setup() 函数完成后再继续 if (__FEATURE_SUSPENSE__ && instance.asyncDep) { parentSuspense && parentSuspense.registerDep(instance, setupRenderEffect)
// Give it a placeholder if this is not hydration // TODO handle self-defined fallback if (!initialVNode.el) { const placeholder = (instance.subTree = createVNode(Comment)) processCommentNode(null, placeholder, container!, anchor) } return }
// 0. create render proxy property access cache instance.accessCache = Object.create(null) // 1. create public instance / render proxy // also mark it raw so it's never observed instance.proxy = markRaw(newProxy(instance.ctx, PublicInstanceProxyHandlers))
if (isPromise(setupResult)) { setupResult.then(unsetCurrentInstance, unsetCurrentInstance) if (isSSR) { // return the promise so server-renderer can wait on it return setupResult .then((resolvedResult: unknown) => { handleSetupResult(instance, resolvedResult, isSSR) }) .catch(e => { handleError(e, instance, ErrorCodes.SETUP_FUNCTION) }) } elseif (__FEATURE_SUSPENSE__) { // async setup returned Promise. // bail here and wait for re-entry. instance.asyncDep = setupResult if (__DEV__ && !instance.suspense) { const name = Component.name ?? 'Anonymous' warn( `Component <${name}>: setup function returned a promise, but no ` + `<Suspense> boundary was found in the parent component tree. ` + `A component with async setup() must be nested in a <Suspense> ` + `in order to be rendered.` ) } } elseif (__DEV__) { warn( `setup() returned a Promise, but the version of Vue you are using ` + `does not support it yet.` ) } } else { handleSetupResult(instance, setupResult, isSSR) } } else { finishComponentSetup(instance, isSSR) } }
let provides = currentInstance.provides // by default an instance inherits its parent's provides object // but when it needs to provide values of its own, it creates its // own provides object using parent provides object as prototype. // this way in `inject` we can simply look up injections from direct // parent and let the prototype chain do the work. const parentProvides = currentInstance.parent && currentInstance.parent.provides if (parentProvides === provides) { provides = currentInstance.provides = Object.create(parentProvides) } // TS doesn't allow symbol as index type provides[key asstring] = value