From eaee515fed56d808043ac8b227f99ee74c63222e Mon Sep 17 00:00:00 2001 From: daiwei Date: Tue, 13 May 2025 17:19:48 +0800 Subject: [PATCH 1/5] feat(vapor): setRef vdom interop --- packages/runtime-core/src/index.ts | 8 ++++++++ packages/runtime-core/src/rendererTemplateRef.ts | 2 +- packages/runtime-vapor/src/apiTemplateRef.ts | 6 +++++- packages/runtime-vapor/src/block.ts | 6 ++++++ packages/runtime-vapor/src/vdomInterop.ts | 16 ++++++++++++++++ 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index e309554f2f6..1e8185dbb39 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -557,3 +557,11 @@ export { startMeasure, endMeasure } from './profiling' * @internal */ export { initFeatureFlags } from './featureFlags' +/** + * @internal + */ +export { setRef } from './rendererTemplateRef' +/** + * @internal + */ +export type { VNodeNormalizedRef } from './vnode' diff --git a/packages/runtime-core/src/rendererTemplateRef.ts b/packages/runtime-core/src/rendererTemplateRef.ts index ca21030dc35..8b5dbe56e37 100644 --- a/packages/runtime-core/src/rendererTemplateRef.ts +++ b/packages/runtime-core/src/rendererTemplateRef.ts @@ -76,7 +76,7 @@ export function setRef( const setupState = owner.setupState const rawSetupState = toRaw(setupState) const canSetSetupRef = - setupState === EMPTY_OBJ + setupState === undefined || setupState === EMPTY_OBJ ? () => false : (key: string) => { if (__DEV__) { diff --git a/packages/runtime-vapor/src/apiTemplateRef.ts b/packages/runtime-vapor/src/apiTemplateRef.ts index c5a6c5fb2b6..967f95e77f2 100644 --- a/packages/runtime-vapor/src/apiTemplateRef.ts +++ b/packages/runtime-vapor/src/apiTemplateRef.ts @@ -20,6 +20,7 @@ import { isString, remove, } from '@vue/shared' +import { isFragment } from './block' export type NodeRef = string | Ref | ((ref: Element) => void) export type RefEl = Element | VaporComponentInstance @@ -47,7 +48,10 @@ export function setRef( refFor = false, ): NodeRef | undefined { if (!instance || instance.isUnmounted) return - + if (isFragment(el) && el.setRef) { + el.setRef(instance, ref, refFor) + return + } const setupState: any = __DEV__ ? instance.setupState || {} : null const refValue = isVaporComponent(el) ? getExposed(el) || el : el diff --git a/packages/runtime-vapor/src/block.ts b/packages/runtime-vapor/src/block.ts index b782afd38d3..a3cd2d3124e 100644 --- a/packages/runtime-vapor/src/block.ts +++ b/packages/runtime-vapor/src/block.ts @@ -8,6 +8,7 @@ import { import { createComment, createTextNode } from './dom/node' import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity' import { isHydrating } from './dom/hydration' +import type { NodeRef } from './apiTemplateRef' export type Block = | Node @@ -23,6 +24,11 @@ export class VaporFragment { anchor?: Node insert?: (parent: ParentNode, anchor: Node | null) => void remove?: (parent?: ParentNode) => void + setRef?: ( + instance: VaporComponentInstance, + ref: NodeRef, + refFor: boolean, + ) => void constructor(nodes: Block) { this.nodes = nodes diff --git a/packages/runtime-vapor/src/vdomInterop.ts b/packages/runtime-vapor/src/vdomInterop.ts index 77228fd72a0..31977583269 100644 --- a/packages/runtime-vapor/src/vdomInterop.ts +++ b/packages/runtime-vapor/src/vdomInterop.ts @@ -8,6 +8,7 @@ import { type ShallowRef, type Slots, type VNode, + type VNodeNormalizedRef, type VaporInteropInterface, createVNode, currentInstance, @@ -16,6 +17,7 @@ import { renderSlot, shallowRef, simpleSetCurrentInstance, + setRef as vdomSetRef, } from '@vue/runtime-dom' import { type LooseRawProps, @@ -33,6 +35,7 @@ import type { RawSlots, VaporSlot } from './componentSlots' import { renderEffect } from './renderEffect' import { createTextNode } from './dom/node' import { optimizePropertyLookup } from './dom/prop' +import type { NodeRef } from './apiTemplateRef' // mounting vapor components and slots in vdom const vaporInteropImpl: Omit< @@ -169,9 +172,12 @@ function createVDOMComponent( : new Proxy(wrapper.slots, vaporSlotsProxyHandler) } + let rawRef: VNodeNormalizedRef | undefined let isMounted = false const parentInstance = currentInstance as VaporComponentInstance const unmount = (parentNode?: ParentNode) => { + // unset ref + if (rawRef) vdomSetRef(rawRef, null, null, vnode, true) internals.umt(vnode.component!, null, !!parentNode) } @@ -186,6 +192,8 @@ function createVDOMComponent( undefined, false, ) + // set ref + if (rawRef) vdomSetRef(rawRef, null, null, vnode) onScopeDispose(unmount, true) isMounted = true } else { @@ -202,6 +210,14 @@ function createVDOMComponent( frag.remove = unmount + frag.setRef = ( + instance: VaporComponentInstance, + ref: NodeRef, + refFor: boolean, + ): void => { + rawRef = { i: instance as any, r: ref as any, k: undefined, f: refFor } + } + return frag } From b9620e84733fb57969e646f30f4d117ddfa5c2eb Mon Sep 17 00:00:00 2001 From: daiwei Date: Wed, 14 May 2025 09:40:09 +0800 Subject: [PATCH 2/5] wip: save --- .../transformTemplateRef.spec.ts.snap | 9 ++++++++ .../transforms/transformTemplateRef.spec.ts | 11 ++++++++++ .../src/generators/templateRef.ts | 22 ++++++++++++++++++- packages/runtime-core/src/index.ts | 2 +- packages/runtime-core/src/vnode.ts | 11 +++++----- packages/runtime-vapor/src/apiTemplateRef.ts | 14 ++++++++++-- packages/runtime-vapor/src/block.ts | 1 + packages/runtime-vapor/src/vdomInterop.ts | 13 +++++++++-- 8 files changed, 71 insertions(+), 12 deletions(-) diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap index f2eade4bcdf..7efbe45f2b9 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap @@ -43,6 +43,15 @@ export function render(_ctx) { }" `; +exports[`compiler: template ref transform > static ref (inline mode) 1`] = ` +" + const _setTemplateRef = _createTemplateRefSetter() + const n0 = t0() + _setTemplateRef(n0, foo, null, null, "foo") + return n0 +" +`; + exports[`compiler: template ref transform > static ref 1`] = ` "import { createTemplateRefSetter as _createTemplateRefSetter, template as _template } from 'vue'; const t0 = _template("
", true) diff --git a/packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts index 6be8f18779c..65bfaeef102 100644 --- a/packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts @@ -1,3 +1,4 @@ +import { BindingTypes } from '@vue/compiler-dom' import { DynamicFlag, type ForIRNode, @@ -48,6 +49,16 @@ describe('compiler: template ref transform', () => { expect(code).contains('_setTemplateRef(n0, "foo")') }) + test('static ref (inline mode)', () => { + const { code } = compileWithTransformRef(`
`, { + inline: true, + bindingMetadata: { foo: BindingTypes.SETUP_REF }, + }) + expect(code).matchSnapshot() + // pass the actual ref and ref key + expect(code).contains('_setTemplateRef(n0, foo, null, null, "foo")') + }) + test('dynamic ref', () => { const { ir, code } = compileWithTransformRef(`
`) diff --git a/packages/compiler-vapor/src/generators/templateRef.ts b/packages/compiler-vapor/src/generators/templateRef.ts index a4d6d546ed3..3aa037a0458 100644 --- a/packages/compiler-vapor/src/generators/templateRef.ts +++ b/packages/compiler-vapor/src/generators/templateRef.ts @@ -2,6 +2,7 @@ import { genExpression } from './expression' import type { CodegenContext } from '../generate' import type { DeclareOldRefIRNode, SetTemplateRefIRNode } from '../ir' import { type CodeFragment, NEWLINE, genCall } from './utils' +import { BindingTypes, type SimpleExpressionNode } from '@vue/compiler-dom' export const setTemplateRefIdent = `_setTemplateRef` @@ -9,15 +10,17 @@ export function genSetTemplateRef( oper: SetTemplateRefIRNode, context: CodegenContext, ): CodeFragment[] { + const [refValue, refKey] = genRefValue(oper.value, context) return [ NEWLINE, oper.effect && `r${oper.element} = `, ...genCall( setTemplateRefIdent, // will be generated in root scope `n${oper.element}`, - genExpression(oper.value, context), + refValue, oper.effect ? `r${oper.element}` : oper.refFor ? 'void 0' : undefined, oper.refFor && 'true', + refKey, ), ] } @@ -25,3 +28,20 @@ export function genSetTemplateRef( export function genDeclareOldRef(oper: DeclareOldRefIRNode): CodeFragment[] { return [NEWLINE, `let r${oper.id}`] } + +function genRefValue(value: SimpleExpressionNode, context: CodegenContext) { + // in inline mode there is no setupState object, so we can't use string + // keys to set the ref. Instead, we need to transform it to pass the + // actual ref instead. + if (!__BROWSER__ && value && context.options.inline) { + const binding = context.options.bindingMetadata[value.content] + if ( + binding === BindingTypes.SETUP_LET || + binding === BindingTypes.SETUP_REF || + binding === BindingTypes.SETUP_MAYBE_REF + ) { + return [[value.content], JSON.stringify(value.content)] + } + } + return [genExpression(value, context)] +} diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 1e8185dbb39..e30bd5abc1a 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -564,4 +564,4 @@ export { setRef } from './rendererTemplateRef' /** * @internal */ -export type { VNodeNormalizedRef } from './vnode' +export { type VNodeNormalizedRef, normalizeRef } from './vnode' diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 4b31151da22..6addb5151ed 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -454,18 +454,17 @@ const createVNodeWithArgsTransform = ( const normalizeKey = ({ key }: VNodeProps): VNode['key'] => key != null ? key : null -const normalizeRef = ({ - ref, - ref_key, - ref_for, -}: VNodeProps): VNodeNormalizedRefAtom | null => { +export const normalizeRef = ( + { ref, ref_key, ref_for }: VNodeProps, + i: ComponentInternalInstance = currentRenderingInstance!, +): VNodeNormalizedRefAtom | null => { if (typeof ref === 'number') { ref = '' + ref } return ( ref != null ? isString(ref) || isRef(ref) || isFunction(ref) - ? { i: currentRenderingInstance, r: ref, k: ref_key, f: !!ref_for } + ? { i, r: ref, k: ref_key, f: !!ref_for } : ref : null ) as any diff --git a/packages/runtime-vapor/src/apiTemplateRef.ts b/packages/runtime-vapor/src/apiTemplateRef.ts index 967f95e77f2..5c2e6ca0205 100644 --- a/packages/runtime-vapor/src/apiTemplateRef.ts +++ b/packages/runtime-vapor/src/apiTemplateRef.ts @@ -22,7 +22,10 @@ import { } from '@vue/shared' import { isFragment } from './block' -export type NodeRef = string | Ref | ((ref: Element) => void) +export type NodeRef = + | string + | Ref + | ((ref: Element | VaporComponentInstance, refs: Record) => void) export type RefEl = Element | VaporComponentInstance export type setRefFn = ( @@ -46,12 +49,16 @@ export function setRef( ref: NodeRef, oldRef?: NodeRef, refFor = false, + refKey?: string, ): NodeRef | undefined { if (!instance || instance.isUnmounted) return + + // vdom interop if (isFragment(el) && el.setRef) { - el.setRef(instance, ref, refFor) + el.setRef(instance, ref, refFor, refKey) return } + const setupState: any = __DEV__ ? instance.setupState || {} : null const refValue = isVaporComponent(el) ? getExposed(el) || el : el @@ -108,6 +115,7 @@ export function setRef( } } else { ref.value = existing + if (refKey) refs[refKey] = existing } } else if (!existing.includes(refValue)) { existing.push(refValue) @@ -119,6 +127,7 @@ export function setRef( } } else if (_isRef) { ref.value = refValue + if (refKey) refs[refKey] = refValue } else if (__DEV__) { warn('Invalid template ref type:', ref, `(${typeof ref})`) } @@ -138,6 +147,7 @@ export function setRef( } } else if (_isRef) { ref.value = null + if (refKey) refs[refKey] = null } }) }) diff --git a/packages/runtime-vapor/src/block.ts b/packages/runtime-vapor/src/block.ts index a3cd2d3124e..f27cb5b59e5 100644 --- a/packages/runtime-vapor/src/block.ts +++ b/packages/runtime-vapor/src/block.ts @@ -28,6 +28,7 @@ export class VaporFragment { instance: VaporComponentInstance, ref: NodeRef, refFor: boolean, + refKey: string | undefined, ) => void constructor(nodes: Block) { diff --git a/packages/runtime-vapor/src/vdomInterop.ts b/packages/runtime-vapor/src/vdomInterop.ts index 31977583269..233524129c7 100644 --- a/packages/runtime-vapor/src/vdomInterop.ts +++ b/packages/runtime-vapor/src/vdomInterop.ts @@ -13,6 +13,7 @@ import { createVNode, currentInstance, ensureRenderer, + normalizeRef, onScopeDispose, renderSlot, shallowRef, @@ -172,7 +173,7 @@ function createVDOMComponent( : new Proxy(wrapper.slots, vaporSlotsProxyHandler) } - let rawRef: VNodeNormalizedRef | undefined + let rawRef: VNodeNormalizedRef | null = null let isMounted = false const parentInstance = currentInstance as VaporComponentInstance const unmount = (parentNode?: ParentNode) => { @@ -214,8 +215,16 @@ function createVDOMComponent( instance: VaporComponentInstance, ref: NodeRef, refFor: boolean, + refKey: string | undefined, ): void => { - rawRef = { i: instance as any, r: ref as any, k: undefined, f: refFor } + rawRef = normalizeRef( + { + ref: ref as any, + ref_for: refFor, + ref_key: refKey, + }, + instance as any, + ) } return frag From 7070f33300cfd26ca408b12a26e549277aa6e7a4 Mon Sep 17 00:00:00 2001 From: daiwei Date: Wed, 14 May 2025 11:03:54 +0800 Subject: [PATCH 3/5] wip: add tests --- packages/runtime-vapor/__tests__/_utils.ts | 51 ++++ .../__tests__/dom/templateRef.spec.ts | 227 +++++++++++++++++- packages/runtime-vapor/src/vdomInterop.ts | 12 +- 3 files changed, 287 insertions(+), 3 deletions(-) diff --git a/packages/runtime-vapor/__tests__/_utils.ts b/packages/runtime-vapor/__tests__/_utils.ts index 0ed64554478..2d9a83e6167 100644 --- a/packages/runtime-vapor/__tests__/_utils.ts +++ b/packages/runtime-vapor/__tests__/_utils.ts @@ -2,6 +2,10 @@ import { createVaporApp } from '../src' import type { App } from '@vue/runtime-dom' import type { VaporComponent, VaporComponentInstance } from '../src/component' import type { RawProps } from '../src/componentProps' +import { compileScript, parse } from '@vue/compiler-sfc' +import * as runtimeVapor from '../src' +import * as runtimeDom from '@vue/runtime-dom' +import * as VueServerRenderer from '@vue/server-renderer' export interface RenderContext { component: VaporComponent @@ -82,3 +86,50 @@ export function makeRender( return define } + +export { runtimeDom, runtimeVapor } +export function compile( + sfc: string, + data: runtimeDom.Ref, + components: Record = {}, + { + vapor = true, + ssr = false, + }: { + vapor?: boolean | undefined + ssr?: boolean | undefined + } = {}, +): any { + if (!sfc.includes(`const data = _data; const components = _components;` + + sfc + } + const descriptor = parse(sfc).descriptor + + const script = compileScript(descriptor, { + id: 'x', + isProd: true, + inlineTemplate: true, + genDefaultAs: '__sfc__', + vapor, + templateOptions: { + ssr, + }, + }) + + const code = + script.content + .replace(/\bimport {/g, 'const {') + .replace(/ as _/g, ': _') + .replace(/} from ['"]vue['"]/g, `} = Vue`) + .replace(/} from "vue\/server-renderer"/g, '} = VueServerRenderer') + + '\nreturn __sfc__' + + return new Function('Vue', 'VueServerRenderer', '_data', '_components', code)( + { ...runtimeDom, ...runtimeVapor }, + VueServerRenderer, + data, + components, + ) +} diff --git a/packages/runtime-vapor/__tests__/dom/templateRef.spec.ts b/packages/runtime-vapor/__tests__/dom/templateRef.spec.ts index e696fadd469..1f2db60c5a5 100644 --- a/packages/runtime-vapor/__tests__/dom/templateRef.spec.ts +++ b/packages/runtime-vapor/__tests__/dom/templateRef.spec.ts @@ -5,11 +5,12 @@ import { createIf, createSlot, createTemplateRefSetter, + delegateEvents, insert, renderEffect, template, } from '../../src' -import { makeRender } from '../_utils' +import { compile, makeRender, runtimeDom, runtimeVapor } from '../_utils' import { type ShallowRef, currentInstance, @@ -716,3 +717,227 @@ describe('api: template ref', () => { // expect(elRef1.value).toBe(elRef2.value) // }) }) + +describe('interop: template ref', () => { + beforeEach(() => { + document.body.innerHTML = '' + }) + + const triggerEvent = (type: string, el: Element) => { + const event = new Event(type, { bubbles: true }) + el.dispatchEvent(event) + } + + delegateEvents('click') + + async function testTemplateRefInterop( + code: string, + components: Record = {}, + data: any = {}, + { vapor = false } = {}, + ) { + const clientComponents: any = {} + for (const key in components) { + const comp = components[key] + const code = comp.code + const isVaporComp = !!comp.vapor + clientComponents[key] = compile(code, data, clientComponents, { + vapor: isVaporComp, + }) + } + + const clientComp = compile(code, data, clientComponents, { + vapor, + }) + + const app = (vapor ? runtimeVapor.createVaporApp : runtimeDom.createApp)( + clientComp, + ) + app.use(runtimeVapor.vaporInteropPlugin) + + const container = document.createElement('div') + document.body.appendChild(container) + app.mount(container) + return { container } + } + + test('vdom app: useTemplateRef on vapor child', async () => { + const { container } = await testTemplateRefInterop( + ` + `, + { + VaporChild: { + code: ` + + + `, + vapor: true, + }, + }, + ) + + expect(container.innerHTML).toBe( + `
foo
`, + ) + + const btn = container.querySelector('.btn') + triggerEvent('click', btn!) + await nextTick() + expect(container.innerHTML).toBe( + `
bar
`, + ) + }) + + test('vdom app: static ref on vapor child', async () => { + const { container } = await testTemplateRefInterop( + ` + `, + { + VaporChild: { + code: ` + + + `, + vapor: true, + }, + }, + ) + + expect(container.innerHTML).toBe( + `
foo
`, + ) + + const btn = container.querySelector('.btn') + triggerEvent('click', btn!) + await nextTick() + expect(container.innerHTML).toBe( + `
bar
`, + ) + }) + + test('vapor app: useTemplateRef on vdom child', async () => { + const { container } = await testTemplateRefInterop( + ` + `, + { + VDOMChild: { + code: ` + + + `, + vapor: false, + }, + }, + undefined, + { vapor: true }, + ) + + expect(container.innerHTML).toBe( + `
foo
`, + ) + + const btn = container.querySelector('.btn') + triggerEvent('click', btn!) + await nextTick() + expect(container.innerHTML).toBe( + `
bar
`, + ) + }) + + test('vapor app: static ref on vdom child', async () => { + const { container } = await testTemplateRefInterop( + ` + `, + { + VDomChild: { + code: ` + + + `, + vapor: false, + }, + }, + undefined, + { vapor: true }, + ) + + expect(container.innerHTML).toBe( + `
foo
`, + ) + + const btn = container.querySelector('.btn') + triggerEvent('click', btn!) + await nextTick() + expect(container.innerHTML).toBe( + `
bar
`, + ) + }) +}) diff --git a/packages/runtime-vapor/src/vdomInterop.ts b/packages/runtime-vapor/src/vdomInterop.ts index 233524129c7..38e29b215ac 100644 --- a/packages/runtime-vapor/src/vdomInterop.ts +++ b/packages/runtime-vapor/src/vdomInterop.ts @@ -30,7 +30,7 @@ import { unmountComponent, } from './component' import { type Block, VaporFragment, insert, remove } from './block' -import { EMPTY_OBJ, extend, isFunction } from '@vue/shared' +import { EMPTY_OBJ, extend, isFunction, isReservedProp } from '@vue/shared' import { type RawProps, rawPropsProxyHandlers } from './componentProps' import type { RawSlots, VaporSlot } from './componentSlots' import { renderEffect } from './renderEffect' @@ -49,7 +49,15 @@ const vaporInteropImpl: Omit< const prev = currentInstance simpleSetCurrentInstance(parentComponent) - const propsRef = shallowRef(vnode.props) + // filter out reserved props + const props: VNode['props'] = {} + for (const key in vnode.props) { + if (!isReservedProp(key)) { + props[key] = vnode.props[key] + } + } + + const propsRef = shallowRef(props) const slotsRef = shallowRef(vnode.children) // @ts-expect-error From 2be0d08de62d272eef7e780afd337f70956fa877 Mon Sep 17 00:00:00 2001 From: daiwei Date: Wed, 14 May 2025 11:17:02 +0800 Subject: [PATCH 4/5] wip: refactor tests --- packages/runtime-vapor/__tests__/_utils.ts | 2 +- .../runtime-vapor/__tests__/hydration.spec.ts | 53 ++----------------- 2 files changed, 6 insertions(+), 49 deletions(-) diff --git a/packages/runtime-vapor/__tests__/_utils.ts b/packages/runtime-vapor/__tests__/_utils.ts index 2d9a83e6167..729d42de78c 100644 --- a/packages/runtime-vapor/__tests__/_utils.ts +++ b/packages/runtime-vapor/__tests__/_utils.ts @@ -87,7 +87,7 @@ export function makeRender( return define } -export { runtimeDom, runtimeVapor } +export { runtimeDom, runtimeVapor, VueServerRenderer } export function compile( sfc: string, data: runtimeDom.Ref, diff --git a/packages/runtime-vapor/__tests__/hydration.spec.ts b/packages/runtime-vapor/__tests__/hydration.spec.ts index 6ba2bf895fb..72d3fe27d64 100644 --- a/packages/runtime-vapor/__tests__/hydration.spec.ts +++ b/packages/runtime-vapor/__tests__/hydration.spec.ts @@ -1,51 +1,6 @@ import { createVaporSSRApp, delegateEvents } from '../src' import { nextTick, ref } from '@vue/runtime-dom' -import { compileScript, parse } from '@vue/compiler-sfc' -import * as runtimeVapor from '../src' -import * as runtimeDom from '@vue/runtime-dom' -import * as VueServerRenderer from '@vue/server-renderer' - -const Vue = { ...runtimeDom, ...runtimeVapor } - -function compile( - sfc: string, - data: runtimeDom.Ref, - components: Record = {}, - ssr = false, -) { - if (!sfc.includes(`const data = _data; const components = _components;` + - sfc - } - const descriptor = parse(sfc).descriptor - - const script = compileScript(descriptor, { - id: 'x', - isProd: true, - inlineTemplate: true, - genDefaultAs: '__sfc__', - vapor: true, - templateOptions: { - ssr, - }, - }) - - const code = - script.content - .replace(/\bimport {/g, 'const {') - .replace(/ as _/g, ': _') - .replace(/} from ['"]vue['"]/g, `} = Vue`) - .replace(/} from "vue\/server-renderer"/g, '} = VueServerRenderer') + - '\nreturn __sfc__' - - return new Function('Vue', 'VueServerRenderer', '_data', '_components', code)( - Vue, - VueServerRenderer, - data, - components, - ) -} +import { VueServerRenderer, compile, runtimeDom } from './_utils' async function testHydration( code: string, @@ -56,10 +11,12 @@ async function testHydration( const clientComponents: any = {} for (const key in components) { clientComponents[key] = compile(components[key], data, clientComponents) - ssrComponents[key] = compile(components[key], data, ssrComponents, true) + ssrComponents[key] = compile(components[key], data, ssrComponents, { + ssr: true, + }) } - const serverComp = compile(code, data, ssrComponents, true) + const serverComp = compile(code, data, ssrComponents, { ssr: true }) const html = await VueServerRenderer.renderToString( runtimeDom.createSSRApp(serverComp), ) From 99ec225e75ac11ec1438f7eb6366078afa0d94b3 Mon Sep 17 00:00:00 2001 From: daiwei Date: Thu, 15 May 2025 08:15:54 +0800 Subject: [PATCH 5/5] chore: tweaks --- .../__tests__/dom/templateRef.spec.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/runtime-vapor/__tests__/dom/templateRef.spec.ts b/packages/runtime-vapor/__tests__/dom/templateRef.spec.ts index 1f2db60c5a5..1073389b974 100644 --- a/packages/runtime-vapor/__tests__/dom/templateRef.spec.ts +++ b/packages/runtime-vapor/__tests__/dom/templateRef.spec.ts @@ -761,11 +761,11 @@ describe('interop: template ref', () => { return { container } } - test('vdom app: useTemplateRef on vapor child', async () => { + test('vdom app: useTemplateRef with vapor child', async () => { const { container } = await testTemplateRefInterop( `