Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement setRef update #191

Merged
merged 10 commits into from
Apr 30, 2024
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`compiler: template ref transform > dynamic ref 1`] = `
"import { setRef as _setRef, template as _template } from 'vue/vapor';
"import { renderEffect as _renderEffect, setRef as _setRef, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")

export function render(_ctx) {
const n0 = t0()
_setRef(n0, _ctx.foo)
let r0
_renderEffect(() => r0 = _setRef(n0, _ctx.foo, r0))
return n0
}"
`;
Expand All @@ -18,7 +19,7 @@ const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = _createFor(() => ([1,2,3]), (_block) => {
const n2 = t0()
_setRef(n2, "foo", true)
_setRef(n2, "foo", void 0, true)
return [n2, () => {}]
})
return n0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`compiler: template ref transform > dynamic ref 1`] = `
"import { setRef as _setRef, template as _template } from 'vue/vapor';
"import { renderEffect as _renderEffect, setRef as _setRef, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")

export function render(_ctx) {
const n0 = t0()
_setRef(n0, _ctx.foo)
let r0
_renderEffect(() => r0 = _setRef(n0, _ctx.foo, r0))
return n0
}"
`;
Expand All @@ -18,7 +19,7 @@ const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = _createFor(() => ([1,2,3]), (_block) => {
const n2 = t0()
_setRef(n2, "foo", true)
_setRef(n2, "foo", void 0, true)
return [n2, () => {}]
})
return n0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ describe('compiler: template ref transform', () => {
},
},
})

expect(code).matchSnapshot()
expect(code).contains('_setRef(n0, "foo")')
})
Expand All @@ -56,21 +55,28 @@ describe('compiler: template ref transform', () => {
flags: DynamicFlag.REFERENCED,
})
expect(ir.template).toEqual(['<div></div>'])
expect(ir.block.operation).lengthOf(1)
expect(ir.block.operation[0]).toMatchObject({
type: IRNodeTypes.SET_TEMPLATE_REF,
element: 0,
value: {
content: 'foo',
isStatic: false,
loc: {
start: { line: 1, column: 12, offset: 11 },
end: { line: 1, column: 15, offset: 14 },
},
expect(ir.block.operation).toMatchObject([
{
type: IRNodeTypes.DECLARE_OLD_REF,
id: 0,
},
})
])
expect(ir.block.effect).toMatchObject([
{
operations: [
{
type: IRNodeTypes.SET_TEMPLATE_REF,
element: 0,
value: {
content: 'foo',
isStatic: false,
},
},
],
},
])
expect(code).matchSnapshot()
expect(code).contains('_setRef(n0, _ctx.foo)')
expect(code).contains('_setRef(n0, _ctx.foo, r0)')
})

test('ref + v-if', () => {
Expand All @@ -82,21 +88,17 @@ describe('compiler: template ref transform', () => {
expect(ir.block.operation[0].type).toBe(IRNodeTypes.IF)

const { positive } = ir.block.operation[0] as IfIRNode

expect(positive.operation).lengthOf(1)
expect(positive.operation[0]).toMatchObject({
type: IRNodeTypes.SET_TEMPLATE_REF,
element: 2,
value: {
content: 'foo',
isStatic: true,
loc: {
start: { line: 1, column: 10, offset: 9 },
end: { line: 1, column: 15, offset: 14 },
expect(positive.operation).toMatchObject([
{
type: IRNodeTypes.SET_TEMPLATE_REF,
element: 2,
value: {
content: 'foo',
isStatic: true,
},
effect: false,
},
})

])
expect(code).matchSnapshot()
expect(code).contains('_setRef(n2, "foo")')
})
Expand All @@ -107,21 +109,19 @@ describe('compiler: template ref transform', () => {
)

const { render } = ir.block.operation[0] as ForIRNode
expect(render.operation).lengthOf(1)
expect(render.operation[0]).toMatchObject({
type: IRNodeTypes.SET_TEMPLATE_REF,
element: 2,
value: {
content: 'foo',
isStatic: true,
loc: {
start: { line: 1, column: 10, offset: 9 },
end: { line: 1, column: 15, offset: 14 },
expect(render.operation).toMatchObject([
{
type: IRNodeTypes.SET_TEMPLATE_REF,
element: 2,
value: {
content: 'foo',
isStatic: true,
},
refFor: true,
effect: false,
},
refFor: true,
})
])
expect(code).matchSnapshot()
expect(code).contains('_setRef(n2, "foo", true)')
expect(code).contains('_setRef(n2, "foo", void 0, true)')
})
})
4 changes: 3 additions & 1 deletion packages/compiler-vapor/src/generators/operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { genSetHtml } from './html'
import { genIf } from './if'
import { genSetModelValue } from './modelValue'
import { genDynamicProps, genSetProp } from './prop'
import { genSetTemplateRef } from './templateRef'
import { genDeclareOldRef, genSetTemplateRef } from './templateRef'
import { genCreateTextNode, genSetText } from './text'
import {
type CodeFragment,
Expand Down Expand Up @@ -59,6 +59,8 @@ export function genOperation(
return genFor(oper, context)
case IRNodeTypes.CREATE_COMPONENT_NODE:
return genCreateComponent(oper, context)
case IRNodeTypes.DECLARE_OLD_REF:
return genDeclareOldRef(oper)
}

return []
Expand Down
8 changes: 7 additions & 1 deletion packages/compiler-vapor/src/generators/templateRef.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { genExpression } from './expression'
import type { CodegenContext } from '../generate'
import type { SetTemplateRefIRNode } from '../ir'
import type { DeclareOldRefIRNode, SetTemplateRefIRNode } from '../ir'
import { type CodeFragment, NEWLINE, genCall } from './utils'

export function genSetTemplateRef(
Expand All @@ -10,11 +10,17 @@ export function genSetTemplateRef(
const { vaporHelper } = context
return [
NEWLINE,
oper.effect && `r${oper.element} = `,
...genCall(
vaporHelper('setRef'),
`n${oper.element}`,
genExpression(oper.value, context),
oper.effect ? `r${oper.element}` : oper.refFor ? 'void 0' : undefined,
oper.refFor && 'true',
),
]
}

export function genDeclareOldRef(oper: DeclareOldRefIRNode): CodeFragment[] {
return [NEWLINE, `let r${oper.id}`]
}
8 changes: 8 additions & 0 deletions packages/compiler-vapor/src/ir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export enum IRNodeTypes {
CREATE_COMPONENT_NODE,

WITH_DIRECTIVE,
DECLARE_OLD_REF, // consider make it more general

IF,
FOR,
Expand Down Expand Up @@ -145,6 +146,7 @@ export interface SetTemplateRefIRNode extends BaseIRNode {
element: number
value: SimpleExpressionNode
refFor: boolean
effect: boolean
}

export interface SetModelValueIRNode extends BaseIRNode {
Expand Down Expand Up @@ -194,6 +196,11 @@ export interface CreateComponentIRNode extends BaseIRNode {
root: boolean
}

export interface DeclareOldRefIRNode extends BaseIRNode {
type: IRNodeTypes.DECLARE_OLD_REF
id: number
}

export type IRNode = OperationNode | RootIRNode
export type OperationNode =
| SetPropIRNode
Expand All @@ -211,6 +218,7 @@ export type OperationNode =
| IfIRNode
| ForIRNode
| CreateComponentIRNode
| DeclareOldRefIRNode

export enum DynamicFlag {
NONE = 0,
Expand Down
17 changes: 13 additions & 4 deletions packages/compiler-vapor/src/transforms/transformTemplateRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import type { NodeTransform } from '../transform'
import { IRNodeTypes } from '../ir'
import { normalizeBindShorthand } from './vBind'
import { findProp } from '../utils'
import { findProp, isConstantExpression } from '../utils'
import { EMPTY_EXPRESSION } from './utils'

export const transformTemplateRef: NodeTransform = (node, context) => {
Expand All @@ -24,11 +24,20 @@ export const transformTemplateRef: NodeTransform = (node, context) => {
: EMPTY_EXPRESSION
}

return () =>
context.registerOperation({
return () => {
const id = context.reference()
const effect = !isConstantExpression(value)
effect &&
context.registerOperation({
type: IRNodeTypes.DECLARE_OLD_REF,
id,
})
context.registerEffect([value], {
type: IRNodeTypes.SET_TEMPLATE_REF,
element: context.reference(),
element: id,
value,
refFor: !!context.inVFor,
effect,
})
}
}
Loading
Loading