Skip to content

Commit 436eda7

Browse files
authored
feat(vapor): template ref vdom interop (#13323)
1 parent 2182e88 commit 436eda7

File tree

12 files changed

+357
-66
lines changed

12 files changed

+357
-66
lines changed

packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ exports[`compiler: template ref transform > static ref (inline mode) 1`] = `
6767
"
6868
const _setTemplateRef = _createTemplateRefSetter()
6969
const n0 = t0()
70-
_setTemplateRef(n0, foo)
70+
_setTemplateRef(n0, foo, null, null, "foo")
7171
return n0
7272
"
7373
`;

packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ describe('compiler: template ref transform', () => {
5555
bindingMetadata: { foo: BindingTypes.SETUP_REF },
5656
})
5757
expect(code).matchSnapshot()
58-
// pass the actual ref
59-
expect(code).contains('_setTemplateRef(n0, foo)')
58+
// pass the actual ref and ref key
59+
expect(code).contains('_setTemplateRef(n0, foo, null, null, "foo")')
6060
})
6161

6262
test('dynamic ref', () => {

packages/compiler-vapor/src/generators/templateRef.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@ export function genSetTemplateRef(
1010
oper: SetTemplateRefIRNode,
1111
context: CodegenContext,
1212
): CodeFragment[] {
13+
const [refValue, refKey] = genRefValue(oper.value, context)
1314
return [
1415
NEWLINE,
1516
oper.effect && `r${oper.element} = `,
1617
...genCall(
1718
setTemplateRefIdent, // will be generated in root scope
1819
`n${oper.element}`,
19-
genRefValue(oper.value, context),
20+
refValue,
2021
oper.effect ? `r${oper.element}` : oper.refFor ? 'void 0' : undefined,
2122
oper.refFor && 'true',
23+
refKey,
2224
),
2325
]
2426
}
@@ -38,8 +40,8 @@ function genRefValue(value: SimpleExpressionNode, context: CodegenContext) {
3840
binding === BindingTypes.SETUP_REF ||
3941
binding === BindingTypes.SETUP_MAYBE_REF
4042
) {
41-
return [value.content]
43+
return [[value.content], JSON.stringify(value.content)]
4244
}
4345
}
44-
return genExpression(value, context)
46+
return [genExpression(value, context)]
4547
}

packages/runtime-core/src/index.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,11 @@ export { Fragment, Text, Comment, Static, type VNodeRef } from './vnode'
114114
// Built-in components
115115
export { Teleport, type TeleportProps } from './components/Teleport'
116116
export { Suspense, type SuspenseProps } from './components/Suspense'
117-
export { KeepAlive, type KeepAliveProps } from './components/KeepAlive'
117+
export {
118+
KeepAlive,
119+
type KeepAliveProps,
120+
type KeepAliveContext,
121+
} from './components/KeepAlive'
118122
export {
119123
BaseTransition,
120124
BaseTransitionPropsValidators,
@@ -563,6 +567,14 @@ export { startMeasure, endMeasure } from './profiling'
563567
* @internal
564568
*/
565569
export { initFeatureFlags } from './featureFlags'
570+
/**
571+
* @internal
572+
*/
573+
export { setRef } from './rendererTemplateRef'
574+
/**
575+
* @internal
576+
*/
577+
export { type VNodeNormalizedRef, normalizeRef } from './vnode'
566578
/**
567579
* @internal
568580
*/

packages/runtime-core/src/rendererTemplateRef.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ export function createCanSetSetupRefChecker(
175175
setupState: Data,
176176
): (key: string) => boolean {
177177
const rawSetupState = toRaw(setupState)
178-
return setupState === EMPTY_OBJ
178+
return setupState === undefined || setupState === EMPTY_OBJ
179179
? NO
180180
: (key: string) => {
181181
if (__DEV__) {

packages/runtime-core/src/vnode.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -455,18 +455,17 @@ const createVNodeWithArgsTransform = (
455455
const normalizeKey = ({ key }: VNodeProps): VNode['key'] =>
456456
key != null ? key : null
457457

458-
const normalizeRef = ({
459-
ref,
460-
ref_key,
461-
ref_for,
462-
}: VNodeProps): VNodeNormalizedRefAtom | null => {
458+
export const normalizeRef = (
459+
{ ref, ref_key, ref_for }: VNodeProps,
460+
i: ComponentInternalInstance = currentRenderingInstance!,
461+
): VNodeNormalizedRefAtom | null => {
463462
if (typeof ref === 'number') {
464463
ref = '' + ref
465464
}
466465
return (
467466
ref != null
468467
? isString(ref) || isRef(ref) || isFunction(ref)
469-
? { i: currentRenderingInstance, r: ref, k: ref_key, f: !!ref_for }
468+
? { i, r: ref, k: ref_key, f: !!ref_for }
470469
: ref
471470
: null
472471
) as any

packages/runtime-vapor/__tests__/_utils.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import { createVaporApp, vaporInteropPlugin } from '../src'
22
import { type App, type Component, createApp } from '@vue/runtime-dom'
33
import type { VaporComponent, VaporComponentInstance } from '../src/component'
44
import type { RawProps } from '../src/componentProps'
5+
import { compileScript, parse } from '@vue/compiler-sfc'
6+
import * as runtimeVapor from '../src'
7+
import * as runtimeDom from '@vue/runtime-dom'
8+
import * as VueServerRenderer from '@vue/server-renderer'
59

610
export interface RenderContext {
711
component: VaporComponent
@@ -136,6 +140,53 @@ export function makeInteropRender(): (comp: Component) => InteropRenderContext {
136140
return define
137141
}
138142

143+
export { runtimeDom, runtimeVapor, VueServerRenderer }
144+
export function compile(
145+
sfc: string,
146+
data: runtimeDom.Ref<any>,
147+
components: Record<string, any> = {},
148+
{
149+
vapor = true,
150+
ssr = false,
151+
}: {
152+
vapor?: boolean | undefined
153+
ssr?: boolean | undefined
154+
} = {},
155+
): any {
156+
if (!sfc.includes(`<script`)) {
157+
sfc =
158+
`<script vapor>const data = _data; const components = _components;</script>` +
159+
sfc
160+
}
161+
const descriptor = parse(sfc).descriptor
162+
163+
const script = compileScript(descriptor, {
164+
id: 'x',
165+
isProd: true,
166+
inlineTemplate: true,
167+
genDefaultAs: '__sfc__',
168+
vapor,
169+
templateOptions: {
170+
ssr,
171+
},
172+
})
173+
174+
const code =
175+
script.content
176+
.replace(/\bimport {/g, 'const {')
177+
.replace(/ as _/g, ': _')
178+
.replace(/} from ['"]vue['"]/g, `} = Vue`)
179+
.replace(/} from "vue\/server-renderer"/g, '} = VueServerRenderer') +
180+
'\nreturn __sfc__'
181+
182+
return new Function('Vue', 'VueServerRenderer', '_data', '_components', code)(
183+
{ ...runtimeDom, ...runtimeVapor },
184+
VueServerRenderer,
185+
data,
186+
components,
187+
)
188+
}
189+
139190
export function shuffle(array: Array<any>): any[] {
140191
let currentIndex = array.length
141192
let temporaryValue

0 commit comments

Comments
 (0)