wip: optimize vapor currentInstance setting

This commit is contained in:
Evan You 2024-12-08 22:32:18 +08:00
parent bb0787b8d4
commit 83be45ea88
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
6 changed files with 65 additions and 36 deletions

View File

@ -74,9 +74,6 @@ if (__SSR__) {
} }
} }
/**
* @internal
*/
export const setCurrentInstance = (instance: GenericComponentInstance) => { export const setCurrentInstance = (instance: GenericComponentInstance) => {
const prev = currentInstance const prev = currentInstance
internalSetCurrentInstance(instance) internalSetCurrentInstance(instance)
@ -91,3 +88,20 @@ export const unsetCurrentInstance = (): void => {
currentInstance && currentInstance.scope.off() currentInstance && currentInstance.scope.off()
internalSetCurrentInstance(null) internalSetCurrentInstance(null)
} }
/**
* Exposed for vapor only. Vapor never runs during SSR so we don't want to pay
* for the extra overhead
* @internal
*/
export const simpleSetCurrentInstance = (
i: GenericComponentInstance | null,
unset?: GenericComponentInstance,
): void => {
currentInstance = i
if (unset) {
unset.scope.off()
} else if (i) {
i.scope.on()
}
}

View File

@ -507,5 +507,8 @@ export {
type AppMountFn, type AppMountFn,
type AppUnmountFn, type AppUnmountFn,
} from './apiCreateApp' } from './apiCreateApp'
export { currentInstance, setCurrentInstance } from './componentCurrentInstance' export {
currentInstance,
simpleSetCurrentInstance,
} from './componentCurrentInstance'
export { registerHMR, unregisterHMR } from './hmr' export { registerHMR, unregisterHMR } from './hmr'

View File

@ -38,7 +38,7 @@ export class DynamicFragment extends Fragment {
// teardown previous branch // teardown previous branch
if (this.scope) { if (this.scope) {
this.scope.off() this.scope.stop()
parent && remove(this.nodes, parent) parent && remove(this.nodes, parent)
// TODO lifecycle unmount // TODO lifecycle unmount
} }

View File

@ -15,7 +15,8 @@ import {
popWarningContext, popWarningContext,
pushWarningContext, pushWarningContext,
registerHMR, registerHMR,
setCurrentInstance, simpleSetCurrentInstance,
unregisterHMR,
warn, warn,
} from '@vue/runtime-dom' } from '@vue/runtime-dom'
import { type Block, isBlock } from './block' import { type Block, isBlock } from './block'
@ -115,7 +116,8 @@ export function createComponent(
} }
const instance = new VaporComponentInstance(component, rawProps, rawSlots) const instance = new VaporComponentInstance(component, rawProps, rawSlots)
const resetCurrentInstance = setCurrentInstance(instance) const prev = currentInstance
simpleSetCurrentInstance(instance)
pauseTracking() pauseTracking()
if (__DEV__) { if (__DEV__) {
@ -146,10 +148,12 @@ export function createComponent(
devRender(instance) devRender(instance)
// HMR // HMR
if (component.__hmrId) {
registerHMR(instance) registerHMR(instance)
instance.hmrRerender = hmrRerender.bind(null, instance) instance.hmrRerender = hmrRerender.bind(null, instance)
instance.hmrReload = hmrReload.bind(null, instance) instance.hmrReload = hmrReload.bind(null, instance)
} }
}
} else { } else {
// in prod result can only be block // in prod result can only be block
instance.block = setupResult as Block instance.block = setupResult as Block
@ -173,7 +177,7 @@ export function createComponent(
popWarningContext() popWarningContext()
} }
resetTracking() resetTracking()
resetCurrentInstance() simpleSetCurrentInstance(prev, instance)
return instance return instance
} }
@ -414,7 +418,11 @@ export function unmountComponent(
parent: ParentNode, parent: ParentNode,
): void { ): void {
if (instance.isMounted && !instance.isUnmounted) { if (instance.isMounted && !instance.isUnmounted) {
if (__DEV__ && instance.type.__hmrId) {
unregisterHMR(instance)
}
if (instance.bum) invokeArrayFns(instance.bum) if (instance.bum) invokeArrayFns(instance.bum)
instance.scope.stop()
// TODO invoke unmount recursively for children // TODO invoke unmount recursively for children
remove(instance.block, parent) remove(instance.block, parent)
// queuePostFlushCb(() => { // queuePostFlushCb(() => {

View File

@ -1,7 +1,8 @@
import { import {
currentInstance,
popWarningContext, popWarningContext,
pushWarningContext, pushWarningContext,
setCurrentInstance, simpleSetCurrentInstance,
} from '@vue/runtime-core' } from '@vue/runtime-core'
import { normalizeBlock } from './block' import { normalizeBlock } from './block'
import { type VaporComponentInstance, devRender } from './component' import { type VaporComponentInstance, devRender } from './component'
@ -12,11 +13,12 @@ export function hmrRerender(instance: VaporComponentInstance): void {
const parent = normalized[0].parentNode! const parent = normalized[0].parentNode!
const anchor = normalized[normalized.length - 1].nextSibling const anchor = normalized[normalized.length - 1].nextSibling
remove(instance.block, parent) remove(instance.block, parent)
const reset = setCurrentInstance(instance) const prev = currentInstance
simpleSetCurrentInstance(instance)
pushWarningContext(instance) pushWarningContext(instance)
devRender(instance) devRender(instance)
reset()
popWarningContext() popWarningContext()
simpleSetCurrentInstance(prev, instance)
insert(instance.block, parent, anchor) insert(instance.block, parent, anchor)
} }

View File

@ -4,7 +4,7 @@ import {
currentInstance, currentInstance,
queueJob, queueJob,
queuePostFlushCb, queuePostFlushCb,
setCurrentInstance, simpleSetCurrentInstance,
warn, warn,
} from '@vue/runtime-dom' } from '@vue/runtime-dom'
import { type VaporComponentInstance, isVaporComponent } from './component' import { type VaporComponentInstance, isVaporComponent } from './component'
@ -16,28 +16,30 @@ export function renderEffect(fn: () => void, noLifecycle = false): void {
warn('renderEffect called without active vapor instance.') warn('renderEffect called without active vapor instance.')
} }
const effect = new ReactiveEffect( const renderEffectFn = noLifecycle
noLifecycle
? fn ? fn
: () => { : () => {
const reset = setCurrentInstance(instance) const prev = currentInstance
const { isMounted, isUpdating, bu, u } = instance simpleSetCurrentInstance(instance)
// before update if (
if (isMounted && !isUpdating && (bu || u)) { instance.isMounted &&
!instance.isUpdating &&
(instance.bu || instance.u)
) {
instance.isUpdating = true instance.isUpdating = true
bu && invokeArrayFns(bu) instance.bu && invokeArrayFns(instance.bu)
fn() fn()
queuePostFlushCb(() => { queuePostFlushCb(() => {
instance.isUpdating = false instance.isUpdating = false
u && invokeArrayFns(u) instance.u && invokeArrayFns(instance.u)
}) })
} else { } else {
fn() fn()
} }
reset() simpleSetCurrentInstance(prev, instance)
}, }
)
const effect = new ReactiveEffect(renderEffectFn)
const job: SchedulerJob = effect.runIfDirty.bind(effect) const job: SchedulerJob = effect.runIfDirty.bind(effect)
job.i = instance job.i = instance
job.id = instance.uid job.id = instance.uid