1import config from '../config'2import Watcher, { WatcherOptions } from '../observer/watcher'3import { mark, measure } from '../util/perf'4import VNode, { createEmptyVNode } from '../vdom/vnode'5import { updateComponentListeners } from './events'6import { resolveSlots } from './render-helpers/resolve-slots'7import { toggleObserving } from '../observer/index'8import { pushTarget, popTarget } from '../observer/dep'9import type { Component } from 'types/component'10import type { MountedComponentVNode } from 'types/vnode'1112import {13 warn,14 noop,15 remove,16 emptyObject,17 validateProp,18 invokeWithErrorHandling19} from '../util/index'20import { currentInstance, setCurrentInstance } from 'v3/currentInstance'21import { getCurrentScope } from 'v3/reactivity/effectScope'22import { syncSetupProxy } from 'v3/apiSetup'2324export let activeInstance: any = null25export let isUpdatingChildComponent: boolean = false2627export function setActiveInstance(vm: Component) {28 const prevActiveInstance = activeInstance29 activeInstance = vm30 return () => {31 activeInstance = prevActiveInstance32 }33}3435export function initLifecycle(vm: Component) {36 const options = vm.$options3738 // locate first non-abstract parent39 let parent = options.parent40 if (parent && !options.abstract) {41 while (parent.$options.abstract && parent.$parent) {42 parent = parent.$parent43 }44 parent.$children.push(vm)45 }4647 vm.$parent = parent48 vm.$root = parent ? parent.$root : vm4950 vm.$children = []51 vm.$refs = {}5253 vm._provided = parent ? parent._provided : Object.create(null)54 vm._watcher = null55 vm._inactive = null56 vm._directInactive = false57 vm._isMounted = false58 vm._isDestroyed = false59 vm._isBeingDestroyed = false60}6162export function lifecycleMixin(Vue: typeof Component) {63 Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {64 const vm: Component = this65 const prevEl = vm.$el66 const prevVnode = vm._vnode67 const restoreActiveInstance = setActiveInstance(vm)68 vm._vnode = vnode69 // Vue.prototype.__patch__ is injected in entry points70 // based on the rendering backend used.71 if (!prevVnode) {72 // initial render73 vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)74 } else {75 // updates76 vm.$el = vm.__patch__(prevVnode, vnode)77 }78 restoreActiveInstance()79 // update __vue__ reference80 if (prevEl) {81 prevEl.__vue__ = null82 }83 if (vm.$el) {84 vm.$el.__vue__ = vm85 }86 // if parent is an HOC, update its $el as well87 let wrapper: Component | undefined = vm88 while (89 wrapper &&90 wrapper.$vnode &&91 wrapper.$parent &&92 wrapper.$vnode === wrapper.$parent._vnode93 ) {94 wrapper.$parent.$el = wrapper.$el95 wrapper = wrapper.$parent96 }97 // updated hook is called by the scheduler to ensure that children are98 // updated in a parent's updated hook.99 }100101 Vue.prototype.$forceUpdate = function () {102 const vm: Component = this103 if (vm._watcher) {104 vm._watcher.update()105 }106 }107108 Vue.prototype.$destroy = function () {109 const vm: Component = this110 if (vm._isBeingDestroyed) {111 return112 }113 callHook(vm, 'beforeDestroy')114 vm._isBeingDestroyed = true115 // remove self from parent116 const parent = vm.$parent117 if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {118 remove(parent.$children, vm)119 }120 // teardown scope. this includes both the render watcher and other121 // watchers created122 vm._scope.stop()123 // remove reference from data ob124 // frozen object may not have observer.125 if (vm._data.__ob__) {126 vm._data.__ob__.vmCount--127 }128 // call the last hook...129 vm._isDestroyed = true130 // invoke destroy hooks on current rendered tree131 vm.__patch__(vm._vnode, null)132 // fire destroyed hook133 callHook(vm, 'destroyed')134 // turn off all instance listeners.135 vm.$off()136 // remove __vue__ reference137 if (vm.$el) {138 vm.$el.__vue__ = null139 }140 // release circular reference (#6759)141 if (vm.$vnode) {142 vm.$vnode.parent = null143 }144 }145}146147export function mountComponent(148 vm: Component,149 el: Element | null | undefined,150 hydrating?: boolean151): Component {152 vm.$el = el153 if (!vm.$options.render) {154 // @ts-expect-error invalid type155 vm.$options.render = createEmptyVNode156 if (__DEV__) {157 /* istanbul ignore if */158 if (159 (vm.$options.template && vm.$options.template.charAt(0) !== '#') ||160 vm.$options.el ||161 el162 ) {163 warn(164 'You are using the runtime-only build of Vue where the template ' +165 'compiler is not available. Either pre-compile the templates into ' +166 'render functions, or use the compiler-included build.',167 vm168 )169 } else {170 warn(171 'Failed to mount component: template or render function not defined.',172 vm173 )174 }175 }176 }177 callHook(vm, 'beforeMount')178179 let updateComponent180 /* istanbul ignore if */181 if (__DEV__ && config.performance && mark) {182 updateComponent = () => {183 const name = vm._name184 const id = vm._uid185 const startTag = `vue-perf-start:${id}`186 const endTag = `vue-perf-end:${id}`187188 mark(startTag)189 const vnode = vm._render()190 mark(endTag)191 measure(`vue ${name} render`, startTag, endTag)192193 mark(startTag)194 vm._update(vnode, hydrating)195 mark(endTag)196 measure(`vue ${name} patch`, startTag, endTag)197 }198 } else {199 updateComponent = () => {200 vm._update(vm._render(), hydrating)201 }202 }203204 const watcherOptions: WatcherOptions = {205 before() {206 if (vm._isMounted && !vm._isDestroyed) {207 callHook(vm, 'beforeUpdate')208 }209 }210 }211212 if (__DEV__) {213 watcherOptions.onTrack = e => callHook(vm, 'renderTracked', [e])214 watcherOptions.onTrigger = e => callHook(vm, 'renderTriggered', [e])215 }216217 // we set this to vm._watcher inside the watcher's constructor218 // since the watcher's initial patch may call $forceUpdate (e.g. inside child219 // component's mounted hook), which relies on vm._watcher being already defined220 new Watcher(221 vm,222 updateComponent,223 noop,224 watcherOptions,225 true /* isRenderWatcher */226 )227 hydrating = false228229 // flush buffer for flush: "pre" watchers queued in setup()230 const preWatchers = vm._preWatchers231 if (preWatchers) {232 for (let i = 0; i < preWatchers.length; i++) {233 preWatchers[i].run()234 }235 }236237 // manually mounted instance, call mounted on self238 // mounted is called for render-created child components in its inserted hook239 if (vm.$vnode == null) {240 vm._isMounted = true241 callHook(vm, 'mounted')242 }243 return vm244}245246export function updateChildComponent(247 vm: Component,248 propsData: Record<string, any> | null | undefined,249 listeners: Record<string, Function | Array<Function>> | undefined,250 parentVnode: MountedComponentVNode,251 renderChildren?: Array<VNode> | null252) {253 if (__DEV__) {254 isUpdatingChildComponent = true255 }256257 // determine whether component has slot children258 // we need to do this before overwriting $options._renderChildren.259260 // check if there are dynamic scopedSlots (hand-written or compiled but with261 // dynamic slot names). Static scoped slots compiled from template has the262 // "$stable" marker.263 const newScopedSlots = parentVnode.data.scopedSlots264 const oldScopedSlots = vm.$scopedSlots265 const hasDynamicScopedSlot = !!(266 (newScopedSlots && !newScopedSlots.$stable) ||267 (oldScopedSlots !== emptyObject && !oldScopedSlots.$stable) ||268 (newScopedSlots && vm.$scopedSlots.$key !== newScopedSlots.$key) ||269 (!newScopedSlots && vm.$scopedSlots.$key)270 )271272 // Any static slot children from the parent may have changed during parent's273 // update. Dynamic scoped slots may also have changed. In such cases, a forced274 // update is necessary to ensure correctness.275 let needsForceUpdate = !!(276 renderChildren || // has new static slots277 vm.$options._renderChildren || // has old static slots278 hasDynamicScopedSlot279 )280281 const prevVNode = vm.$vnode282 vm.$options._parentVnode = parentVnode283 vm.$vnode = parentVnode // update vm's placeholder node without re-render284285 if (vm._vnode) {286 // update child tree's parent287 vm._vnode.parent = parentVnode288 }289 vm.$options._renderChildren = renderChildren290291 // update $attrs and $listeners hash292 // these are also reactive so they may trigger child update if the child293 // used them during render294 const attrs = parentVnode.data.attrs || emptyObject295 if (vm._attrsProxy) {296 // force update if attrs are accessed and has changed since it may be297 // passed to a child component.298 if (299 syncSetupProxy(300 vm._attrsProxy,301 attrs,302 (prevVNode.data && prevVNode.data.attrs) || emptyObject,303 vm,304 '$attrs'305 )306 ) {307 needsForceUpdate = true308 }309 }310 vm.$attrs = attrs311312 // update listeners313 listeners = listeners || emptyObject314 const prevListeners = vm.$options._parentListeners315 if (vm._listenersProxy) {316 syncSetupProxy(317 vm._listenersProxy,318 listeners,319 prevListeners || emptyObject,320 vm,321 '$listeners'322 )323 }324 vm.$listeners = vm.$options._parentListeners = listeners325 updateComponentListeners(vm, listeners, prevListeners)326327 // update props328 if (propsData && vm.$options.props) {329 toggleObserving(false)330 const props = vm._props331 const propKeys = vm.$options._propKeys || []332 for (let i = 0; i < propKeys.length; i++) {333 const key = propKeys[i]334 const propOptions: any = vm.$options.props // wtf flow?335 props[key] = validateProp(key, propOptions, propsData, vm)336 }337 toggleObserving(true)338 // keep a copy of raw propsData339 vm.$options.propsData = propsData340 }341342 // resolve slots + force update if has children343 if (needsForceUpdate) {344 vm.$slots = resolveSlots(renderChildren, parentVnode.context)345 vm.$forceUpdate()346 }347348 if (__DEV__) {349 isUpdatingChildComponent = false350 }351}352353function isInInactiveTree(vm) {354 while (vm && (vm = vm.$parent)) {355 if (vm._inactive) return true356 }357 return false358}359360export function activateChildComponent(vm: Component, direct?: boolean) {361 if (direct) {362 vm._directInactive = false363 if (isInInactiveTree(vm)) {364 return365 }366 } else if (vm._directInactive) {367 return368 }369 if (vm._inactive || vm._inactive === null) {370 vm._inactive = false371 for (let i = 0; i < vm.$children.length; i++) {372 activateChildComponent(vm.$children[i])373 }374 callHook(vm, 'activated')375 }376}377378export function deactivateChildComponent(vm: Component, direct?: boolean) {379 if (direct) {380 vm._directInactive = true381 if (isInInactiveTree(vm)) {382 return383 }384 }385 if (!vm._inactive) {386 vm._inactive = true387 for (let i = 0; i < vm.$children.length; i++) {388 deactivateChildComponent(vm.$children[i])389 }390 callHook(vm, 'deactivated')391 }392}393394export function callHook(395 vm: Component,396 hook: string,397 args?: any[],398 setContext = true399) {400 // #7573 disable dep collection when invoking lifecycle hooks401 pushTarget()402 const prevInst = currentInstance403 const prevScope = getCurrentScope()404 setContext && setCurrentInstance(vm)405 const handlers = vm.$options[hook]406 const info = `${hook} hook`407 if (handlers) {408 for (let i = 0, j = handlers.length; i < j; i++) {409 invokeWithErrorHandling(handlers[i], vm, args || null, vm, info)410 }411 }412 if (vm._hasHookEvent) {413 vm.$emit('hook:' + hook)414 }415 if (setContext) {416 setCurrentInstance(prevInst)417 prevScope && prevScope.on()418 }419420 popTarget()421}
Findings
✓ No findings reported for this file.