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