revert: "refactor: remove update function from compiler"

Bad for performance, so revert it temporarily

This reverts commit be65b98a33.
This commit is contained in:
三咲智子 Kevin Deng 2024-02-12 22:01:42 +08:00
parent bf5f7c389b
commit 66cea4b325
No known key found for this signature in database
GPG Key ID: 69992F2250DFD93E
5 changed files with 60 additions and 42 deletions

View File

@ -1,7 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`compiler: v-for > basic v-for 1`] = `
"import { children as _children, on as _on, renderEffect as _renderEffect, setText as _setText, createFor as _createFor, template as _template } from 'vue/vapor';
"import { children as _children, on as _on, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
@ -9,33 +9,32 @@ export function render(_ctx) {
const n2 = t0()
const n3 = _children(n2, 0)
_on(n3, "click", () => $event => (_ctx.remove(_block.s[0])))
_renderEffect(() => {
const _updateEffect = () => {
const [item] = _block.s
_setText(n3, item)
})
return n2
}
_renderEffect(_updateEffect)
return [n2, _updateEffect]
}, (item) => (item.id))
return [n1]
}"
`;
exports[`compiler: v-for > multi effect 1`] = `
"import { children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, createFor as _createFor, template as _template } from 'vue/vapor';
"import { children as _children, setDynamicProp as _setDynamicProp, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n1 = _createFor(() => (_ctx.items), (_block) => {
const n2 = t0()
const n3 = _children(n2, 0)
_renderEffect(() => {
const _updateEffect = () => {
const [item, index] = _block.s
_setDynamicProp(n3, "item", item)
})
_renderEffect(() => {
const [item, index] = _block.s
_setDynamicProp(n3, "index", index)
})
return n2
}
_renderEffect(_updateEffect)
return [n2, _updateEffect]
})
return [n1]
}"
@ -48,7 +47,7 @@ const t0 = _template("<div>item</div>")
export function render(_ctx) {
const n1 = _createFor(() => (_ctx.items), (_block) => {
const n2 = t0()
return n2
return [n2, () => {}]
})
return [n1]
}"

View File

@ -21,13 +21,14 @@ export function genBlockFunction(
oper: BlockFunctionIRNode,
context: CodegenContext,
args: CodeFragment[] = [],
returnValue?: () => CodeFragment[],
): CodeFragment[] {
return [
'(',
...args,
') => {',
INDENT_START,
...genBlockFunctionContent(oper, context),
...genBlockFunctionContent(oper, context, returnValue),
INDENT_END,
NEWLINE,
'}',
@ -37,6 +38,7 @@ export function genBlockFunction(
export function genBlockFunctionContent(
ir: BlockFunctionIRNode | RootIRNode,
context: CodegenContext,
returnValue?: () => CodeFragment[],
): CodeFragment[] {
const [frag, push] = buildCodeFragment()
@ -55,6 +57,7 @@ export function genBlockFunctionContent(
push(...genOperations(ir.operation, context))
push(...(context.genEffect || genEffects)(ir.effect, context))
if (ir.returns) {
push(
NEWLINE,
@ -62,7 +65,11 @@ export function genBlockFunctionContent(
...genMulti(['[', ']', ', '], ...ir.returns.map(n => `n${n}`)),
)
} else {
push(NEWLINE, `return n${ir.dynamic.id}`)
push(
NEWLINE,
'return ',
...(returnValue ? returnValue() : [`n${ir.dynamic.id}`]),
)
}
return frag

View File

@ -3,7 +3,7 @@ import { genBlockFunction } from './block'
import { genExpression } from './expression'
import type { CodegenContext } from '../generate'
import type { ForIRNode, IREffect } from '../ir'
import { genOperation } from './operation'
import { genOperations } from './operation'
import {
type CodeFragment,
INDENT_END,
@ -24,14 +24,19 @@ export function genFor(
const rawKey = key && key.content
const sourceExpr = ['() => (', ...genExpression(source, context), ')']
let updateFn = '_updateEffect'
context.genEffect = genEffectInFor
const idMap: Record<string, string> = {}
if (rawValue) idMap[rawValue] = `_block.s[0]`
if (rawKey) idMap[rawKey] = `_block.s[1]`
const blockRet = (): CodeFragment[] => [
`[n${render.dynamic.id!}, ${updateFn}]`,
]
const blockFn = context.withId(
() => genBlockFunction(render, context, ['_block']),
() => genBlockFunction(render, context, ['_block'], blockRet),
idMap,
)
@ -63,16 +68,15 @@ export function genFor(
]
function genEffectInFor(effects: IREffect[]): CodeFragment[] {
const [frag, push] = buildCodeFragment()
if (!effects.length) {
updateFn = '() => {}'
return []
}
const idMap: Record<string, string | null> = {}
if (value) idMap[value.content] = null
if (key) idMap[key.content] = null
let statement: CodeFragment[] = []
const [frag, push] = buildCodeFragment(INDENT_START)
// const [value, key] = _block.s
if (rawValue || rawKey) {
// const [value, key] = _block.s
statement = [
push(
NEWLINE,
'const ',
'[',
@ -80,22 +84,28 @@ export function genFor(
rawKey && ', ',
rawKey && [rawKey, NewlineType.None, key.loc],
'] = _block.s',
]
)
}
const idMap: Record<string, string | null> = {}
if (value) idMap[value.content] = null
if (key) idMap[key.content] = null
context.withId(() => {
for (const { operations } of effects) {
push(
NEWLINE,
`${vaporHelper('renderEffect')}(() => {`,
INDENT_START,
...statement,
)
operations.forEach(op => push(...genOperation(op, context)))
push(INDENT_END, NEWLINE, '})')
}
effects.forEach(effect =>
push(...genOperations(effect.operations, context)),
)
}, idMap)
return frag
push(INDENT_END)
return [
NEWLINE,
`const ${updateFn} = () => {`,
...frag,
NEWLINE,
'}',
NEWLINE,
`${vaporHelper('renderEffect')}(${updateFn})`,
]
}
}

View File

@ -24,11 +24,12 @@ describe('createFor', () => {
() => sortedList.value,
block => {
const n3 = createTextNode()
renderEffect(() => {
const update = () => {
const [item] = block.s
setText(n3, item.name)
})
return [n3]
}
renderEffect(update)
return [n3, update]
},
)
return [n1]

View File

@ -15,7 +15,7 @@ interface ForBlock extends Fragment {
/*! #__NO_SIDE_EFFECTS__ */
export const createFor = (
src: () => any[] | Record<string, string> | Set<any> | Map<any, any>,
renderItem: (block: ForBlock) => Block,
renderItem: (block: ForBlock) => [Block, () => void],
getKey?: (item: any, index: number) => any,
getMemo?: (item: any) => any[],
hydrationNode?: Node,
@ -46,8 +46,9 @@ export const createFor = (
memo: getMemo && getMemo(item),
[fragmentKey]: true,
})
block.nodes = scope.run(() => renderItem(block))!
block.update = () => scope.effects.forEach(effect => effect.run())
const res = scope.run(() => renderItem(block))!
block.nodes = res[0]
block.update = res[1]
if (getMemo) block.update()
if (parent) insert(block.nodes, parent, anchor)
return block