mirror of https://github.com/vuejs/core.git
test(vapor): renderEffect
This commit is contained in:
parent
2bbb6d2fc5
commit
ec23ab9e3a
|
@ -1,18 +1,17 @@
|
||||||
import {
|
import { createVaporApp, defineVaporComponent } from '../src'
|
||||||
type App,
|
import type { App } from '@vue/runtime-dom'
|
||||||
type Component,
|
import type {
|
||||||
type ComponentInternalInstance,
|
ObjectVaporComponent,
|
||||||
type ObjectComponent,
|
VaporComponent,
|
||||||
type SetupFn,
|
VaporComponentInstance,
|
||||||
createVaporApp,
|
VaporSetupFn,
|
||||||
defineComponent,
|
} from '../src/component'
|
||||||
} from '../src/_old'
|
import type { RawProps } from '../src/componentProps'
|
||||||
import type { RawProps } from '../src/_old/componentProps'
|
|
||||||
|
|
||||||
export interface RenderContext {
|
export interface RenderContext {
|
||||||
component: Component
|
component: VaporComponent
|
||||||
host: HTMLElement
|
host: HTMLElement
|
||||||
instance: ComponentInternalInstance | undefined
|
instance: VaporComponentInstance | undefined
|
||||||
app: App
|
app: App
|
||||||
create: (props?: RawProps) => RenderContext
|
create: (props?: RawProps) => RenderContext
|
||||||
mount: (container?: string | ParentNode) => RenderContext
|
mount: (container?: string | ParentNode) => RenderContext
|
||||||
|
@ -21,7 +20,7 @@ export interface RenderContext {
|
||||||
html: () => string
|
html: () => string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeRender<C = ObjectComponent | SetupFn>(
|
export function makeRender<C = ObjectVaporComponent | VaporSetupFn>(
|
||||||
initHost = (): HTMLDivElement => {
|
initHost = (): HTMLDivElement => {
|
||||||
const host = document.createElement('div')
|
const host = document.createElement('div')
|
||||||
host.setAttribute('id', 'host')
|
host.setAttribute('id', 'host')
|
||||||
|
@ -42,8 +41,8 @@ export function makeRender<C = ObjectComponent | SetupFn>(
|
||||||
})
|
})
|
||||||
|
|
||||||
function define(comp: C) {
|
function define(comp: C) {
|
||||||
const component = defineComponent(comp as any)
|
const component = defineVaporComponent(comp as any)
|
||||||
let instance: ComponentInternalInstance | undefined
|
let instance: VaporComponentInstance | undefined
|
||||||
let app: App
|
let app: App
|
||||||
|
|
||||||
function render(
|
function render(
|
||||||
|
@ -61,7 +60,7 @@ export function makeRender<C = ObjectComponent | SetupFn>(
|
||||||
}
|
}
|
||||||
|
|
||||||
function mount(container: string | ParentNode = host) {
|
function mount(container: string | ParentNode = host) {
|
||||||
instance = app.mount(container)
|
instance = app.mount(container) as any as VaporComponentInstance
|
||||||
return res()
|
return res()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
import {
|
import {
|
||||||
EffectScope,
|
EffectScope,
|
||||||
|
type GenericComponentInstance,
|
||||||
|
currentInstance,
|
||||||
getCurrentScope,
|
getCurrentScope,
|
||||||
nextTick,
|
nextTick,
|
||||||
onBeforeUpdate,
|
onBeforeUpdate,
|
||||||
onEffectCleanup,
|
|
||||||
onUpdated,
|
onUpdated,
|
||||||
ref,
|
ref,
|
||||||
renderEffect,
|
|
||||||
template,
|
|
||||||
watchEffect,
|
watchEffect,
|
||||||
watchPostEffect,
|
watchPostEffect,
|
||||||
watchSyncEffect,
|
watchSyncEffect,
|
||||||
} from '../src/_old'
|
} from '@vue/runtime-dom'
|
||||||
import {
|
import { renderEffect, template } from '../src'
|
||||||
type ComponentInternalInstance,
|
import { onEffectCleanup } from '@vue/reactivity'
|
||||||
currentInstance,
|
|
||||||
} from '../src/_old/component'
|
|
||||||
import { makeRender } from './_utils'
|
import { makeRender } from './_utils'
|
||||||
|
|
||||||
const define = makeRender<any>()
|
const define = makeRender<any>()
|
||||||
|
@ -110,8 +107,10 @@ describe('renderEffect', () => {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
).render()
|
).render()
|
||||||
|
|
||||||
const { change, changeRender } = instance?.setupState as any
|
const { change, changeRender } = instance?.setupState as any
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
expect(calls).toEqual(['pre 0', 'sync 0', 'renderEffect 0', 'post 0'])
|
expect(calls).toEqual(['pre 0', 'sync 0', 'renderEffect 0', 'post 0'])
|
||||||
calls.length = 0
|
calls.length = 0
|
||||||
|
|
||||||
|
@ -126,8 +125,8 @@ describe('renderEffect', () => {
|
||||||
expect(calls).toEqual([
|
expect(calls).toEqual([
|
||||||
'pre cleanup 0',
|
'pre cleanup 0',
|
||||||
'pre 1',
|
'pre 1',
|
||||||
'beforeUpdate 1',
|
|
||||||
'renderEffect cleanup 0',
|
'renderEffect cleanup 0',
|
||||||
|
'beforeUpdate 1',
|
||||||
'renderEffect 1',
|
'renderEffect 1',
|
||||||
'post cleanup 0',
|
'post cleanup 0',
|
||||||
'post 1',
|
'post 1',
|
||||||
|
@ -146,8 +145,8 @@ describe('renderEffect', () => {
|
||||||
expect(calls).toEqual([
|
expect(calls).toEqual([
|
||||||
'pre cleanup 1',
|
'pre cleanup 1',
|
||||||
'pre 2',
|
'pre 2',
|
||||||
'beforeUpdate 2',
|
|
||||||
'renderEffect cleanup 1',
|
'renderEffect cleanup 1',
|
||||||
|
'beforeUpdate 2',
|
||||||
'renderEffect 2',
|
'renderEffect 2',
|
||||||
'post cleanup 1',
|
'post cleanup 1',
|
||||||
'post 2',
|
'post 2',
|
||||||
|
@ -174,6 +173,7 @@ describe('renderEffect', () => {
|
||||||
},
|
},
|
||||||
).render()
|
).render()
|
||||||
const { update } = instance?.setupState as any
|
const { update } = instance?.setupState as any
|
||||||
|
|
||||||
await expect(async () => {
|
await expect(async () => {
|
||||||
update()
|
update()
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
@ -182,6 +182,9 @@ describe('renderEffect', () => {
|
||||||
expect(
|
expect(
|
||||||
'[Vue warn]: Unhandled error during execution of beforeUpdate hook',
|
'[Vue warn]: Unhandled error during execution of beforeUpdate hook',
|
||||||
).toHaveBeenWarned()
|
).toHaveBeenWarned()
|
||||||
|
expect(
|
||||||
|
'[Vue warn]: Unhandled error during execution of component update',
|
||||||
|
).toHaveBeenWarned()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('errors should include the execution location with updated hook', async () => {
|
test('errors should include the execution location with updated hook', async () => {
|
||||||
|
@ -204,6 +207,7 @@ describe('renderEffect', () => {
|
||||||
).render()
|
).render()
|
||||||
|
|
||||||
const { update } = instance?.setupState as any
|
const { update } = instance?.setupState as any
|
||||||
|
|
||||||
await expect(async () => {
|
await expect(async () => {
|
||||||
update()
|
update()
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
@ -217,15 +221,17 @@ describe('renderEffect', () => {
|
||||||
test('should be called with the current instance and current scope', async () => {
|
test('should be called with the current instance and current scope', async () => {
|
||||||
const source = ref(0)
|
const source = ref(0)
|
||||||
const scope = new EffectScope()
|
const scope = new EffectScope()
|
||||||
let instanceSnap: ComponentInternalInstance | null = null
|
let instanceSnap: GenericComponentInstance | null = null
|
||||||
let scopeSnap: EffectScope | undefined = undefined
|
let scopeSnap: EffectScope | undefined = undefined
|
||||||
const { instance } = define(() => {
|
const { instance } = define(() => {
|
||||||
scope.run(() => {
|
scope.run(() => {
|
||||||
renderEffect(() => {
|
renderEffect(() => {
|
||||||
|
source.value
|
||||||
instanceSnap = currentInstance
|
instanceSnap = currentInstance
|
||||||
scopeSnap = getCurrentScope()
|
scopeSnap = getCurrentScope()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
return []
|
||||||
}).render()
|
}).render()
|
||||||
|
|
||||||
expect(instanceSnap).toBe(instance)
|
expect(instanceSnap).toBe(instance)
|
||||||
|
|
|
@ -34,8 +34,7 @@ export const createVaporApp: CreateAppFunction<
|
||||||
ParentNode,
|
ParentNode,
|
||||||
VaporComponent
|
VaporComponent
|
||||||
> = comp => {
|
> = comp => {
|
||||||
if (!_createApp)
|
if (!_createApp) _createApp = createAppAPI(mountApp, unmountApp, i => i)
|
||||||
_createApp = createAppAPI(mountApp, unmountApp, i => i.exposed)
|
|
||||||
const app = _createApp(comp)
|
const app = _createApp(comp)
|
||||||
const mount = app.mount
|
const mount = app.mount
|
||||||
app.mount = (container, ...args: any[]) => {
|
app.mount = (container, ...args: any[]) => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ReactiveEffect } from '@vue/reactivity'
|
import { ReactiveEffect, getCurrentScope } from '@vue/reactivity'
|
||||||
import {
|
import {
|
||||||
type SchedulerJob,
|
type SchedulerJob,
|
||||||
currentInstance,
|
currentInstance,
|
||||||
|
@ -12,7 +12,8 @@ import { invokeArrayFns } from '@vue/shared'
|
||||||
|
|
||||||
export function renderEffect(fn: () => void, noLifecycle = false): void {
|
export function renderEffect(fn: () => void, noLifecycle = false): void {
|
||||||
const instance = currentInstance as VaporComponentInstance
|
const instance = currentInstance as VaporComponentInstance
|
||||||
if (__DEV__ && !isVaporComponent(instance)) {
|
const scope = getCurrentScope()
|
||||||
|
if (__DEV__ && !__TEST__ && !isVaporComponent(instance)) {
|
||||||
warn('renderEffect called without active vapor instance.')
|
warn('renderEffect called without active vapor instance.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +22,9 @@ export function renderEffect(fn: () => void, noLifecycle = false): void {
|
||||||
: () => {
|
: () => {
|
||||||
const prev = currentInstance
|
const prev = currentInstance
|
||||||
simpleSetCurrentInstance(instance)
|
simpleSetCurrentInstance(instance)
|
||||||
|
if (scope) scope.on()
|
||||||
if (
|
if (
|
||||||
|
instance &&
|
||||||
instance.isMounted &&
|
instance.isMounted &&
|
||||||
!instance.isUpdating &&
|
!instance.isUpdating &&
|
||||||
(instance.bu || instance.u)
|
(instance.bu || instance.u)
|
||||||
|
@ -36,17 +39,19 @@ export function renderEffect(fn: () => void, noLifecycle = false): void {
|
||||||
} else {
|
} else {
|
||||||
fn()
|
fn()
|
||||||
}
|
}
|
||||||
|
if (scope) scope.off()
|
||||||
simpleSetCurrentInstance(prev, instance)
|
simpleSetCurrentInstance(prev, instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
const effect = new ReactiveEffect(renderEffectFn)
|
const effect = new ReactiveEffect(renderEffectFn)
|
||||||
const job: SchedulerJob = effect.runIfDirty.bind(effect)
|
const job: SchedulerJob = effect.runIfDirty.bind(effect)
|
||||||
job.i = instance
|
if (instance) {
|
||||||
job.id = instance.uid
|
job.i = instance
|
||||||
|
job.id = instance.uid
|
||||||
|
}
|
||||||
effect.scheduler = () => queueJob(job)
|
effect.scheduler = () => queueJob(job)
|
||||||
effect.run()
|
effect.run()
|
||||||
|
|
||||||
// TODO lifecycle
|
|
||||||
// TODO recurse handling
|
// TODO recurse handling
|
||||||
// TODO measure
|
// TODO measure
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue