diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap index 7739fcb0c..3d1368b74 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap @@ -1,18 +1,15 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`compiler: v-for > array de-structured value 1`] = ` -"import { renderEffect as _renderEffect, setText as _setText, createFor as _createFor, template as _template } from 'vue/vapor'; +"import { renderEffect as _renderEffect, setText as _setText, withDestructure as _withDestructure, createFor as _createFor, template as _template } from 'vue/vapor'; const t0 = _template("
") export function render(_ctx) { - const n0 = _createFor(() => (_ctx.list), (_ctx0) => { + const n0 = _createFor(() => (_ctx.list), _withDestructure((_state, [[id, ...other], index] = _state) => [id, other, index], (_ctx0) => { const n2 = t0() _renderEffect(() => _setText(n2, _ctx0[0] + _ctx0[1] + _ctx0[2])) return n2 - }, ([id, ...other], index) => (id), null, null, false, _state => { - const [[id, ...other], index] = _state - return [id, other, index] - }) + }), ([id, ...other], index) => (id)) return n0 }" `; @@ -69,35 +66,29 @@ export function render(_ctx) { `; exports[`compiler: v-for > object de-structured value 1`] = ` -"import { renderEffect as _renderEffect, setText as _setText, createFor as _createFor, template as _template } from 'vue/vapor'; +"import { renderEffect as _renderEffect, setText as _setText, withDestructure as _withDestructure, createFor as _createFor, template as _template } from 'vue/vapor'; const t0 = _template("
") export function render(_ctx) { - const n0 = _createFor(() => (_ctx.list), (_ctx0) => { + const n0 = _createFor(() => (_ctx.list), _withDestructure((_state, [{ id, ...other }, index] = _state) => [id, other, index], (_ctx0) => { const n2 = t0() _renderEffect(() => _setText(n2, _ctx0[0] + _ctx0[1] + _ctx0[2])) return n2 - }, ({ id, ...other }, index) => (id), null, null, false, _state => { - const [{ id, ...other }, index] = _state - return [id, other, index] - }) + }), ({ id, ...other }, index) => (id)) return n0 }" `; exports[`compiler: v-for > v-for aliases w/ complex expressions 1`] = ` -"import { renderEffect as _renderEffect, setText as _setText, createFor as _createFor, template as _template } from 'vue/vapor'; +"import { renderEffect as _renderEffect, setText as _setText, withDestructure as _withDestructure, createFor as _createFor, template as _template } from 'vue/vapor'; const t0 = _template("
") export function render(_ctx) { - const n0 = _createFor(() => (_ctx.list), (_ctx0) => { + const n0 = _createFor(() => (_ctx.list), _withDestructure((_state, [{ foo = bar, baz: [qux = quux] }] = _state) => [foo, qux], (_ctx0) => { const n2 = t0() _renderEffect(() => _setText(n2, _ctx0[0] + _ctx.bar + _ctx.baz + _ctx0[1] + _ctx.quux)) return n2 - }, null, null, null, false, _state => { - const [{ foo = bar, baz: [qux = quux] }] = _state - return [foo, qux] - }) + })) return n0 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/vFor.spec.ts b/packages/compiler-vapor/__tests__/transforms/vFor.spec.ts index f457ac745..f3fa72a47 100644 --- a/packages/compiler-vapor/__tests__/transforms/vFor.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vFor.spec.ts @@ -129,7 +129,9 @@ describe('compiler: v-for', () => { `
{{ id + other + index }}
`, ) expect(code).matchSnapshot() - expect(code).contains(`return [id, other, index]`) + expect(code).contains( + `(_state, [{ id, ...other }, index] = _state) => [id, other, index]`, + ) expect(code).contains(`_ctx0[0] + _ctx0[1] + _ctx0[2]`) expect(ir.block.operation[0]).toMatchObject({ type: IRNodeTypes.FOR, @@ -162,7 +164,9 @@ describe('compiler: v-for', () => { `
{{ id + other + index }}
`, ) expect(code).matchSnapshot() - expect(code).contains(`return [id, other, index]`) + expect(code).contains( + `(_state, [[id, ...other], index] = _state) => [id, other, index]`, + ) expect(code).contains(`_ctx0[0] + _ctx0[1] + _ctx0[2]`) expect(ir.block.operation[0]).toMatchObject({ type: IRNodeTypes.FOR, @@ -197,7 +201,9 @@ describe('compiler: v-for', () => { `, ) expect(code).matchSnapshot() - expect(code).contains(`return [foo, qux]`) + expect(code).contains( + `(_state, [{ foo = bar, baz: [qux = quux] }] = _state) => [foo, qux]`, + ) expect(code).contains( `_ctx0[0] + _ctx.bar + _ctx.baz + _ctx0[1] + _ctx.quux`, ) diff --git a/packages/compiler-vapor/src/generators/for.ts b/packages/compiler-vapor/src/generators/for.ts index 9c3b962f9..c8d74342c 100644 --- a/packages/compiler-vapor/src/generators/for.ts +++ b/packages/compiler-vapor/src/generators/for.ts @@ -6,8 +6,6 @@ import type { ForIRNode } from '../ir' import { type CodeFragment, DELIMITERS_ARRAY, - INDENT_END, - INDENT_START, NEWLINE, genCall, genMulti, @@ -51,7 +49,7 @@ export function genFor( if (rawKey) idMap[rawKey] = `${propsName}[${idsOfValue.size}]` if (rawIndex) idMap[rawIndex] = `${propsName}[${idsOfValue.size + 1}]` - const blockFn = context.withId( + let blockFn = context.withId( () => genBlock(render, context, [propsName]), idMap, ) @@ -77,31 +75,28 @@ export function genFor( ] } - let destructureAssignmentFn: CodeFragment[] | false = false if (isDestructureAssignment) { const idMap: Record = {} idsOfValue.forEach(id => (idMap[id] = null)) if (rawKey) idMap[rawKey] = null if (rawIndex) idMap[rawIndex] = null - destructureAssignmentFn = [ - '_state => {', - INDENT_START, - NEWLINE, - 'const ', + const destructureAssignmentFn: CodeFragment[] = [ + '(_state, ', ...genMulti( DELIMITERS_ARRAY, rawValue ? rawValue : rawKey || rawIndex ? '_' : undefined, rawKey ? rawKey : rawIndex ? '__' : undefined, rawIndex, ), - ' = _state', - NEWLINE, - 'return ', + ' = _state) => ', ...genMulti(DELIMITERS_ARRAY, ...idsOfValue, rawKey, rawIndex), - INDENT_END, - NEWLINE, - '}', ] + + blockFn = genCall( + vaporHelper('withDestructure'), + destructureAssignmentFn, + blockFn, + ) } return [ @@ -114,8 +109,7 @@ export function genFor( getKeyFn, false, // todo: getMemo false, // todo: hydrationNode - (once && 'true') || (destructureAssignmentFn && 'false'), - destructureAssignmentFn, + once && 'true', ), ] } diff --git a/packages/runtime-vapor/__tests__/for.spec.ts b/packages/runtime-vapor/__tests__/for.spec.ts index 2d028d069..c1d981cb2 100644 --- a/packages/runtime-vapor/__tests__/for.spec.ts +++ b/packages/runtime-vapor/__tests__/for.spec.ts @@ -7,6 +7,7 @@ import { renderEffect, shallowRef, template, + withDestructure, withDirectives, } from '../src' import { makeRender } from './_utils' @@ -318,25 +319,24 @@ describe('createFor', () => { const { host } = define(() => { const n1 = createFor( () => list.value, - state => { - const span = document.createElement('li') - renderEffect(() => { - const [name, key, index] = state - span.innerHTML = `${key}. ${name}` - - // index should be undefined if source is not an object - expect(index).toBe(undefined) - }) - return span - }, + withDestructure( + state => { + const [{ name }, key, index] = state + return [name, key, index] + }, + state => { + const span = document.createElement('li') + renderEffect(() => { + const [name, key, index] = state + span.innerHTML = `${key}. ${name}` + + // index should be undefined if source is not an object + expect(index).toBe(undefined) + }) + return span + }, + ), item => item.name, - undefined, - undefined, - false, - state => { - const [{ name }, key, index] = state - return [name, key, index] - }, ) return n1 }).render() diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 446141700..07bbd151f 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -26,7 +26,6 @@ import { invokeWithUpdate, } from './directivesChildFragment' import type { DynamicSlot } from './componentSlots' -import { destructuring } from './destructuring' interface ForBlock extends Fragment { scope: BlockEffectScope @@ -49,7 +48,6 @@ export const createFor = ( getMemo?: (item: any, key: any, index?: number) => any[], hydrationNode?: Node, once?: boolean, - assignment?: (state: any[]) => any[], ): Fragment => { let isMounted = false let oldBlocks: ForBlock[] = [] @@ -283,11 +281,7 @@ export const createFor = ( memo: getMemo && getMemo(item, key, index), [fragmentKey]: true, }) - const proxyState = proxyRefs(state) - const itemCtx = assignment - ? destructuring(scope, proxyState, assignment) - : proxyState - block.nodes = scope.run(() => renderItem(itemCtx))! + block.nodes = scope.run(() => renderItem(proxyRefs(state)))! invokeWithMount(scope, () => { // TODO v-memo diff --git a/packages/runtime-vapor/src/destructure.ts b/packages/runtime-vapor/src/destructure.ts new file mode 100644 index 000000000..20030dd32 --- /dev/null +++ b/packages/runtime-vapor/src/destructure.ts @@ -0,0 +1,19 @@ +import { shallowReactive } from '@vue/reactivity' +import { renderEffect } from './renderEffect' + +export function withDestructure

( + assign: (...args: P) => any[], + block: (ctx: any[]) => R, +): (...args: P) => R { + return (...args: P) => { + const ctx = shallowReactive([]) + renderEffect(() => { + const res = assign(...args) + const len = res.length + for (let i = 0; i < len; i++) { + ctx[i] = res[i] + } + }) + return block(ctx) + } +} diff --git a/packages/runtime-vapor/src/destructuring.ts b/packages/runtime-vapor/src/destructuring.ts deleted file mode 100644 index 255130dac..000000000 --- a/packages/runtime-vapor/src/destructuring.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { type EffectScope, shallowReactive } from '@vue/reactivity' -import { renderEffect } from './renderEffect' - -export function destructuring( - scope: EffectScope, - state: any, - fn: (state: any) => any[], -) { - const list = shallowReactive([]) - scope.run(() => { - renderEffect(() => { - const res = fn(state) - const len = res.length - for (let i = 0; i < len; i++) { - list[i] = res[i] - } - }) - }) - return list -} diff --git a/packages/runtime-vapor/src/index.ts b/packages/runtime-vapor/src/index.ts index 79a0b26a6..60810713e 100644 --- a/packages/runtime-vapor/src/index.ts +++ b/packages/runtime-vapor/src/index.ts @@ -135,6 +135,8 @@ export { createComponent } from './apiCreateComponent' export { resolveComponent, resolveDirective } from './helpers/resolveAssets' export { toHandlers } from './helpers/toHandlers' +export { withDestructure } from './destructure' + // **Internal** DOM-only runtime directive helpers export { vModelText,