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) => {
const prev = currentInstance
internalSetCurrentInstance(instance)
@ -91,3 +88,20 @@ export const unsetCurrentInstance = (): void => {
currentInstance && currentInstance.scope.off()
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 AppUnmountFn,
} from './apiCreateApp'
export { currentInstance, setCurrentInstance } from './componentCurrentInstance'
export {
currentInstance,
simpleSetCurrentInstance,
} from './componentCurrentInstance'
export { registerHMR, unregisterHMR } from './hmr'

View File

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

View File

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

View File

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

View File

@ -4,7 +4,7 @@ import {
currentInstance,
queueJob,
queuePostFlushCb,
setCurrentInstance,
simpleSetCurrentInstance,
warn,
} from '@vue/runtime-dom'
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.')
}
const effect = new ReactiveEffect(
noLifecycle
const renderEffectFn = noLifecycle
? fn
: () => {
const reset = setCurrentInstance(instance)
const { isMounted, isUpdating, bu, u } = instance
// before update
if (isMounted && !isUpdating && (bu || u)) {
const prev = currentInstance
simpleSetCurrentInstance(instance)
if (
instance.isMounted &&
!instance.isUpdating &&
(instance.bu || instance.u)
) {
instance.isUpdating = true
bu && invokeArrayFns(bu)
instance.bu && invokeArrayFns(instance.bu)
fn()
queuePostFlushCb(() => {
instance.isUpdating = false
u && invokeArrayFns(u)
instance.u && invokeArrayFns(instance.u)
})
} else {
fn()
}
reset()
},
)
simpleSetCurrentInstance(prev, instance)
}
const effect = new ReactiveEffect(renderEffectFn)
const job: SchedulerJob = effect.runIfDirty.bind(effect)
job.i = instance
job.id = instance.uid